69 Commits

Author SHA1 Message Date
proddy
e8f57b6343 v3.8.1 2026-01-11 19:28:38 +01:00
proddy
a1ab81de66 Merge branch 'dev' 2026-01-11 19:14:11 +01:00
proddy
28135c225b Merge branch 'dev' 2025-12-31 21:26:15 +01:00
proddy
eaa277fef0 v3.7.2 2025-03-22 10:32:03 +01:00
proddy
e418b7d8e7 fix routing in tabs - #2264 2024-11-30 21:31:42 +01:00
proddy
a4e3be6a69 3.7.1 changelog 2024-11-29 10:30:14 +01:00
proddy
a1bc5bb055 3.7.1 2024-11-29 10:30:05 +01:00
proddy
f444ca31e0 Merge remote-tracking branch 'origin/dev' 2024-10-27 11:41:47 +01:00
proddy
1b70b55989 update demo url 2024-08-10 14:58:48 +02:00
proddy
1487f30c43 Merge remote-tracking branch 'origin/dev' for 3.6.5 2024-03-23 17:56:05 +01:00
Proddy
e00eb8e64f 3.6.4 2023-11-26 20:11:36 +01:00
Proddy
f41bb3671c 3.6.4 2023-11-24 07:36:36 +01:00
Proddy
22c75e6df3 3.6.4 2023-11-24 07:36:29 +01:00
proddy
5ab10b7aa6 fixes #1450 2023-11-22 09:48:09 +01:00
Proddy
ee5fd4d0eb 3.6.3 2023-11-21 14:40:47 +01:00
Proddy
46f35bc67c another patch on 3.6.3 2023-11-21 14:40:32 +01:00
Proddy
ec85a7ec24 3.6.3 (refershed) 2023-11-19 21:24:01 +01:00
Proddy
02f2389587 add workflow_dispatch: 2023-11-18 18:51:12 +01:00
Proddy
7f140021aa quick fix - https://github.com/emsesp/EMS-ESP32/pull/1438 2023-11-18 18:47:28 +01:00
Proddy
6796962c1e 3.6.3 2023-11-18 13:35:20 +01:00
Proddy
df6de21cf4 Merge remote-tracking branch 'origin/dev' 2023-11-18 13:35:04 +01:00
Proddy
df9f75a5c9 updated yarn for 3.6.2 2023-10-01 17:42:54 +02:00
Proddy
7bd8710eb6 3.6.2 2023-10-01 17:40:09 +02:00
Proddy
32f2c6d341 Merge remote-tracking branch 'origin/dev' 2023-10-01 17:40:02 +02:00
Proddy
86919c1684 Merge branch 'origin/dev' 2023-09-09 14:12:07 +02:00
Proddy
86e29515e7 build s3 2023-08-15 18:44:24 +02:00
Proddy
46eb4185d7 update with 3.6.0 2023-08-13 14:37:13 +02:00
Proddy
8da6761a48 Merge branch 'dev' 2023-08-13 14:32:41 +02:00
Proddy
9233f0dfcc v3.5.1 - merge with patch 2023-03-11 16:06:05 +01:00
Proddy
292f743b14 Update bug_report.md 2023-02-19 11:18:08 +01:00
Proddy
dd6dfffd57 Delete questions---troubleshooting.md 2023-02-19 10:49:52 +01:00
Proddy
ec705a5307 Delete feature_request.md 2023-02-19 10:49:45 +01:00
Proddy
f45f071710 Create config.yml 2023-02-19 10:49:32 +01:00
Proddy
f3858546de Merge branch 'origin/dev' 2023-02-06 21:58:27 +01:00
Proddy
d0ac0b7804 update with version on dev 2022-10-30 16:58:37 +01:00
Proddy
d8284ec09f Merge pull request #705 from MichaelDvP/main
v3.4.4 Fix for new installations with filesystem not initializing
2022-10-29 10:46:41 +02:00
MichaelDvP
6e982acde8 v3.4.4 Fix for new installations with filesystem not initializing 2022-10-28 10:50:51 +02:00
Proddy
8c94ce99b2 quick fix for filesystem initialization 2022-10-08 09:23:00 +02:00
proddy
fc057d18c9 Merge remote-tracking branch 'origin/dev' 2022-09-18 14:33:23 +02:00
Proddy
18e9b99413 Merge remote-tracking branch 'origin/dev' into main 2022-05-29 16:16:38 +02:00
Proddy
a47e0e8266 update for 3.4.0 2022-05-23 21:20:45 +02:00
Proddy
f412ddc716 Merge remote-tracking branch 'origin/dev' into main 2022-05-23 21:20:36 +02:00
proddy
29110e96e5 Merge remote-tracking branch 'origin/dev' 2022-01-20 10:51:40 +01:00
proddy
b65866217a 3.4.0 2021-11-28 23:03:28 +01:00
proddy
611e3b1243 Merge remote-tracking branch 'origin/dev' 2021-11-28 23:03:15 +01:00
proddy
2ca0a0c634 v3.2.1 merged from dev 2021-08-08 14:46:14 +02:00
proddy
7eb1f061b7 Merge remote-tracking branch 'origin/dev' for 3.2.0 release 2021-08-06 12:06:08 +02:00
proddy
50459a23fe force v16 of nodejs 2021-06-26 11:13:07 +02:00
proddy
5bf53c3389 3.1.1 2021-06-26 11:03:03 +02:00
proddy
4b7aa95be3 Merge remote-tracking branch 'origin/dev' 2021-06-26 11:02:55 +02:00
Proddy
70943f5758 Update pre_release.yml 2021-05-16 15:52:09 +02:00
Proddy
3bc280b817 Delete check_code.yml 2021-05-16 15:51:56 +02:00
Proddy
62b15a5319 Update pre_release.yml 2021-05-16 15:35:06 +02:00
Proddy
8dd18802d6 Update tagged_release.yml 2021-05-16 15:34:45 +02:00
proddy
57a516a83a updated README and images 2021-05-09 15:13:16 +02:00
proddy
a57fdaa4b3 Merge remote-tracking branch 'origin/dev' into main 2021-05-04 12:21:51 +02:00
proddy
4841e42286 Merge remote-tracking branch 'origin/dev' into main 2021-03-30 16:35:18 +02:00
proddy
8c2d2b06ed cleaned up old changelog 2021-03-18 20:59:09 +01:00
proddy
38c8b1b7f0 3.0.0 2021-03-18 20:58:21 +01:00
proddy
6fb5933a02 Merge remote-tracking branch 'origin/dev' into main 2021-03-18 20:58:12 +01:00
proddy
c0944433be remove workspace.code-workspace 2021-03-16 17:41:42 +01:00
Proddy
478e6362c9 Merge pull request #27 from FauthD:main
Add global names to Dallas sensors to avoid ugly <unknown> and other …
2021-03-16 17:39:00 +01:00
fauthd
4d6354db78 Add stuff to gitignore, add vscode workspace 2021-03-16 16:47:09 +01:00
fauthd
beab0f0c77 Add global names to Dallas sensors to avoid ugly <unknown> and other issues in HA 2021-03-16 16:00:23 +01:00
Proddy
c17749bd22 Update README.md 2021-03-14 23:43:33 +01:00
proddy
2bad769c5c build: include assets 2021-03-14 21:20:51 +01:00
proddy
8ad89ca64b move repo 2021-03-14 21:05:15 +01:00
proddy
9244d8daec Semantic Commit Messages 2021-03-14 18:10:57 +01:00
proddy
02d01334b2 update new build 2021-03-14 17:37:18 +01:00
178 changed files with 7441 additions and 10690 deletions

View File

@@ -22,7 +22,7 @@ _Make sure your have performed every step and checked the applicable boxes befor
- [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues) - [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues)
- [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions) - [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
- [ ] Searched the issue in the [docs](https://emsesp.org/Troubleshooting/) - [ ] Searched the issue in the [docs](https://emsesp.org/Troubleshooting/)
- [ ] Searched the issue in the [chat](https://discord.gg/GP9DPSgeJq) - [ ] Searched the issue in the [chat](https://discord.gg/3J3GgnzpyT)
- [ ] Provide the System information in the area below, taken from `http://<IP>/api/system` - [ ] Provide the System information in the area below, taken from `http://<IP>/api/system`
```json ```json

View File

@@ -7,5 +7,5 @@ contact_links:
url: https://github.com/emsesp/EMS-ESP32/discussions url: https://github.com/emsesp/EMS-ESP32/discussions
about: EMS-ESP usage Questions, Feature Requests and Projects. about: EMS-ESP usage Questions, Feature Requests and Projects.
- name: EMS-ESP Users Chat - name: EMS-ESP Users Chat
url: https://discord.gg/GP9DPSgeJq url: https://discord.gg/3J3GgnzpyT
about: Chat for feedback, questions and troubleshooting. about: Chat for feedback, questions and troubleshooting.

View File

@@ -33,7 +33,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- board profile `CUSTOM` can only be selected in developer mode - board profile `CUSTOM` can only be selected in developer mode
- mqtt sends round values without decimals (`28` instead of `28.0`) - mqtt sends round values without decimals (`28` instead of `28.0`)
## [3.8.0] 31 December 2025 ## [3.8.0] 31 December 2025
## Added ## Added

View File

@@ -6,31 +6,6 @@ For more details go to [emsesp.org](https://emsesp.org/).
## Added ## Added
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
- e-mail notification using ReadyMail Client
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
## Fixed ## Fixed
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
## Changed ## Changed
- weblogbuffer up to 1000 messages with PSRAM, mentioned in [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
- validate custom entity writes, [#2931](https://github.com/emsesp/EMS-ESP32/issues/2931)
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
- translated modes `heat` and `eco` for HA-climate mode-str-tpl
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
- use tasmota core 2026.03.30
- secure mqtt uses ESP_SSLClient
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
- move http client from stack to heap

View File

@@ -52,20 +52,19 @@ INCLUDES := src/core src/devices src/web src/test lib_standalone lib/* lib/semv
LIBRARIES := LIBRARIES :=
CPPCHECK = cppcheck CPPCHECK = cppcheck
CHECKFLAGS = -q --force --std=gnu++20 CHECKFLAGS = -q --force --std=gnu++17
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Languages Standard # Languages Standard
#---------------------------------------------------------------------- #----------------------------------------------------------------------
C_STANDARD := -std=c20 C_STANDARD := -std=c17
CXX_STANDARD := -std=gnu++20 CXX_STANDARD := -std=gnu++17
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Defined Symbols # Defined Symbols
#---------------------------------------------------------------------- #----------------------------------------------------------------------
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500 DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
DEFINES += -DNO_TLS_SUPPORT
DEFINES += $(ARGS) DEFINES += $(ARGS)
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
@@ -80,10 +79,6 @@ SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null) CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null) CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
# Exclude files not needed for standalone build, if they exist
CSOURCES := $(filter-out src/core/ModuleLibrary.c,$(CSOURCES))
CXXSOURCES := $(filter-out src/core/ModuleLibrary.cpp,$(CXXSOURCES))
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES))) OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES))) DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))

View File

@@ -18,7 +18,7 @@
<a href="https://emsesp.org"> <a href="https://emsesp.org">
<img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" /> <img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" />
</a> </a>
<a href="https://discord.gg/GP9DPSgeJq"> <a href="https://discord.gg/3J3GgnzpyT">
<img src="https://img.shields.io/badge/Discord-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" /> <img src="https://img.shields.io/badge/Discord-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
</a> </a>
<a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md"> <a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md">
@@ -32,8 +32,7 @@
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=emsesp_EMS-ESP32&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=emsesp_EMS-ESP32) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=emsesp_EMS-ESP32&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=emsesp_EMS-ESP32)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9441142f49424ef891e8f5251866ee6b)](https://app.codacy.com/gh/emsesp/EMS-ESP32/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/9441142f49424ef891e8f5251866ee6b)](https://app.codacy.com/gh/emsesp/EMS-ESP32/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![downloads](https://img.shields.io/github/downloads/emsesp/EMS-ESP32/total.svg)](https://github.com/emsesp/EMS-ESP32/releases) [![downloads](https://img.shields.io/github/downloads/emsesp/EMS-ESP32/total.svg)](https://github.com/emsesp/EMS-ESP32/releases)
[![chat](https://img.shields.io/discord/816637840644505620.svg?style=flat-square&color=blueviolet)](https://discord.gg/GP9DPSgeJq) [![chat](https://img.shields.io/discord/816637840644505620.svg?style=flat-square&color=blueviolet)](https://discord.gg/3J3GgnzpyT)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/emsesp/EMS-ESP32)
[![GitHub stars](https://img.shields.io/github/stars/emsesp/EMS-ESP32.svg?style=social&label=Star)](https://github.com/emsesp/EMS-ESP32/stargazers) [![GitHub stars](https://img.shields.io/github/stars/emsesp/EMS-ESP32.svg?style=social&label=Star)](https://github.com/emsesp/EMS-ESP32/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/emsesp/EMS-ESP32.svg?style=social&label=Fork)](https://github.com/emsesp/EMS-ESP32/network) [![GitHub forks](https://img.shields.io/github/forks/emsesp/EMS-ESP32.svg?style=social&label=Fork)](https://github.com/emsesp/EMS-ESP32/network)
@@ -41,8 +40,7 @@
**EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller to communicate with **EMS** (Energy Management System) compatible equipment from manufacturers such as Bosch, Buderus, Nefit, Junkers, Worcester, Sieger, elm.leblanc and iVT. **EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller to communicate with **EMS** (Energy Management System) compatible equipment from manufacturers such as Bosch, Buderus, Nefit, Junkers, Worcester, Sieger, elm.leblanc and iVT.
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl>. These gateways are tested thoroughly and certified to work with EMS-ESP. It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl> or custom built.
## 📦&nbsp; **Key Features** ## 📦&nbsp; **Key Features**
@@ -66,17 +64,17 @@ Head over to the [Installation Guide](https://emsesp.org/Installing) section of
## 📋&nbsp; **Documentation** ## 📋&nbsp; **Documentation**
Visit [emsesp.org](https://emsesp.org) for more details on how to setup and configure EMS-ESP. You'll also find more a collection of example configuarations, Frequently Asked Questions and Troubleshooting tips. Visit [emsesp.org](https://emsesp.org) for more details on how to install and configure EMS-ESP. There is also a collection of Frequently Asked Questions and Troubleshooting tips with example customizations from the community.
## 💬&nbsp; **Getting Support** ## 💬&nbsp; **Getting Support**
To chat with the community reach out on our [Discord Server](https://discord.gg/GP9DPSgeJq). To chat with the community reach out on our [Discord Server](https://discord.gg/3J3GgnzpyT).
If you find an issue or have a request, see the [Getting Support](https://emsesp.org/Support/) section of the documentation. Note if you are using a non-BBQKees EMS gateway, you may need to contact the manufacturer for support. If you find an issue or have a request, see [how to request support](https://emsesp.org/Support/) on how to submit a bug report or feature request.
## 🎥&nbsp; **Live Demo** ## 🎥&nbsp; **Live Demo**
To see a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language and use any username and password to log in. Note whast you're seeing is static example data so not all features are operational. For a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language from the sign on page and log in with any username or password. Note not all features are operational as it's based on static data.
## 💖&nbsp; **Contributors** ## 💖&nbsp; **Contributors**
@@ -86,7 +84,7 @@ If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it
## 📦&nbsp; **Building** ## 📦&nbsp; **Building**
See the [Building the firmware](https://emsesp.org/Building) guide in the documentation for instructions on how to build EMS-ESP from this source code. See the [Building Guide](https://emsesp.org/Building) section of the documentation for instructions on how to build EMS-ESP.
## 📢&nbsp; **Libraries used** ## 📢&nbsp; **Libraries used**

View File

@@ -5,7 +5,7 @@
}, },
"core": "esp32", "core": "esp32",
"extra_flags": [ "extra_flags": [
"-DNO_TLS_SUPPORT", "-DTASMOTA_SDK",
"-DARDUINO_LOLIN_C3_MINI", "-DARDUINO_LOLIN_C3_MINI",
"-DARDUINO_USB_MODE=1", "-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=1" "-DARDUINO_USB_CDC_ON_BOOT=1"

View File

@@ -6,7 +6,7 @@
"core": "esp32", "core": "esp32",
"extra_flags": [ "extra_flags": [
"-DBOARD_HAS_PSRAM", "-DBOARD_HAS_PSRAM",
"-DNO_TLS_SUPPORT", "-DTASMOTA_SDK",
"-DARDUINO_USB_CDC_ON_BOOT=1", "-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0" "-DARDUINO_USB_MODE=0"
], ],

View File

@@ -21,7 +21,7 @@
"arduino", "arduino",
"espidf" "espidf"
], ],
"name": "Tasmota ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS", "name": "Espressif ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
"upload": { "upload": {
"flash_size": "32MB", "flash_size": "32MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,

View File

@@ -1,7 +1,7 @@
{ {
"build": { "build": {
"core": "esp32", "core": "esp32",
"extra_flags": "-DNO_TLS_SUPPORT", "extra_flags": "-DTASMOTA_SDK",
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "40000000L", "f_flash": "40000000L",
"flash_mode": "dio", "flash_mode": "dio",
@@ -19,7 +19,7 @@
"arduino", "arduino",
"espidf" "espidf"
], ],
"name": "Tasmota ESP32 16M Flash, 4608KB Code/OTA, 2MB FS", "name": "Espressif ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
"upload": { "upload": {
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,

View File

@@ -19,7 +19,7 @@
"arduino", "arduino",
"espidf" "espidf"
], ],
"name": "Tasmota ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS", "name": "Espressif ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
"upload": { "upload": {
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,

View File

@@ -1,7 +1,7 @@
{ {
"build": { "build": {
"core": "esp32", "core": "esp32",
"extra_flags": "-DNO_TLS_SUPPORT", "extra_flags": "-DTASMOTA_SDK",
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "40000000L", "f_flash": "40000000L",
"flash_mode": "dio", "flash_mode": "dio",

View File

@@ -2,7 +2,6 @@
"build": { "build": {
"core": "esp32", "core": "esp32",
"extra_flags": [ "extra_flags": [
"-DNO_TLS_SUPPORT",
"-DARDUINO_XIAO_ESP32C6", "-DARDUINO_XIAO_ESP32C6",
"-DARDUINO_USB_MODE=1", "-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=1" "-DARDUINO_USB_CDC_ON_BOOT=1"

View File

@@ -9,7 +9,6 @@
} }
], ],
"dictionaries": ["project-words"], "dictionaries": ["project-words"],
"caseSensitive": false,
"ignorePaths": [ "ignorePaths": [
"node_modules", "node_modules",
"compile_commands.json", "compile_commands.json",
@@ -37,7 +36,6 @@
"pnpm-*.yaml", "pnpm-*.yaml",
"vite.config.ts", "vite.config.ts",
"lib/esp32-psram/**", "lib/esp32-psram/**",
"test/test_api/test_api.h", "test/test_api/test_api.h"
"lib_standalone/**"
] ]
} }

View File

@@ -1,228 +1,85 @@
{ {
"type": "systembackup", "type": "settings",
"version": "3.8.2", "Network": {
"date": "2026-03-29T13:28:15", "ssid": "my_wifi_ssid",
"systembackup": [ "bssid": "",
{ "password": "my_wifi_password",
"type": "settings", "hostname": "ems-esp"
"Network": {
"ssid": "",
"bssid": "",
"password": "",
"hostname": "ems-esp",
"static_ip_config": false,
"bandwidth20": false,
"nosleep": true,
"enableMDNS": true,
"enableCORS": false,
"CORSOrigin": "*",
"tx_power": 0
},
"AP": {
"provision_mode": 2,
"ssid": "ems-esp",
"password": "ems-esp-neo",
"channel": 1,
"ssid_hidden": false,
"max_clients": 4,
"local_ip": "192.168.4.1",
"gateway_ip": "192.168.4.1",
"subnet_mask": "255.255.255.0"
},
"MQTT": {
"enableTLS": false,
"rootCA": "",
"enabled": false,
"host": "",
"port": 1883,
"base": "ems-esp",
"username": "",
"password": "",
"client_id": "esp32-b8ffc9ec",
"keep_alive": 60,
"clean_session": false,
"entity_format": 1,
"publish_time_boiler": 10,
"publish_time_thermostat": 10,
"publish_time_solar": 10,
"publish_time_mixer": 10,
"publish_time_water": 10,
"publish_time_other": 60,
"publish_time_sensor": 10,
"publish_time_heartbeat": 60,
"mqtt_qos": 0,
"mqtt_retain": false,
"ha_enabled": false,
"nested_format": 1,
"discovery_prefix": "homeassistant",
"discovery_type": 0,
"ha_number_mode": 0,
"publish_single": false,
"publish_single2cmd": false,
"send_response": false
},
"NTP": {
"enabled": true,
"server": "time.google.com",
"tz_label": "Europe/Amsterdam",
"tz_format": "CET-1CEST,M3.5.0,M10.5.0/3"
},
"Security": {
"jwt_secret": "ems-esp-neo",
"users": [
{
"username": "admin",
"password": "admin",
"admin": true
},
{
"username": "guest",
"password": "guest",
"admin": false
}
]
},
"Settings": {
"version": "3.8.2",
"board_profile": "E32V2_2",
"platform": "ESP32",
"locale": "en",
"tx_mode": 1,
"ems_bus_id": 11,
"syslog_enabled": false,
"syslog_level": 3,
"trace_raw": false,
"syslog_mark_interval": 0,
"syslog_host": "",
"syslog_port": 514,
"boiler_heatingoff": false,
"remote_timeout": 24,
"remote_timeout_en": false,
"shower_timer": false,
"shower_alert": false,
"shower_alert_coldshot": 10,
"shower_alert_trigger": 7,
"shower_min_duration": 180,
"rx_gpio": 4,
"tx_gpio": 5,
"dallas_gpio": 14,
"dallas_parasite": false,
"led_gpio": 32,
"hide_led": false,
"led_type": 1,
"low_clock": false,
"telnet_enabled": true,
"notoken_api": false,
"readonly_mode": false,
"analog_enabled": true,
"pbutton_gpio": 34,
"solar_maxflow": 30,
"fahrenheit": false,
"bool_format": 1,
"bool_dashboard": 1,
"enum_format": 1,
"weblog_level": 6,
"weblog_buffer": 50,
"weblog_compact": true,
"phy_type": 1,
"eth_power": 15,
"eth_phy_addr": 0,
"eth_clock_mode": 1,
"modbus_enabled": false,
"modbus_port": 502,
"modbus_max_clients": 10,
"modbus_timeout": 300,
"developer_mode": true,
"email_enabled": false,
"email_ssl": false,
"email_starttls": true,
"email_server": "smtp.example.net",
"email_port": 587,
"email_login": "",
"email_pass": "",
"email_sender": "ems-esp@example.net",
"email_recp": "",
"email_subject": "ems-esp notification"
}
}, },
{ "AP": {
"type": "schedule", "provision_mode": 2,
"Schedule": { "ssid": "ems-esp",
"schedule": [] "password": "ems-esp-neo",
} "channel": 1,
"ssid_hidden": false,
"max_clients": 4,
"local_ip": "192.168.4.1",
"gateway_ip": "192.168.4.1",
"subnet_mask": "255.255.255.0"
}, },
{ "MQTT": {
"type": "customizations", "enableTLS": false,
"Customizations": { "rootCA": "",
"ts": [ "enabled": false,
{ "host": "127.0.0.1",
"id": "28_1767_7B13_2502", "port": 1883,
"name": "gateway_temperature", "base": "ems-esp",
"offset": 0, "username": "username",
"is_system": true "password": "password",
} "client_id": "ems-esp",
], "entity_format": 1,
"as": [ "publish_time_boiler": 10,
{ "publish_time_thermostat": 10,
"gpio": 39, "publish_time_solar": 10,
"name": "core_voltage", "publish_time_mixer": 10,
"offset": 0, "publish_time_water": 10,
"factor": 0.003771, "publish_time_other": 60,
"uom": 23, "publish_time_sensor": 10,
"type": 3, "publish_time_heartbeat": 60,
"is_system": true "mqtt_qos": 0,
}, "mqtt_retain": false,
{ "ha_enabled": false,
"gpio": 36, "nested_format": 1,
"name": "supply_voltage", "discovery_prefix": "homeassistant",
"offset": 0, "discovery_type": 0,
"factor": 0.017, "publish_single": false,
"uom": 23, "publish_single2cmd": false,
"type": 3, "send_response": false
"is_system": true
},
{
"gpio": 2,
"name": "led",
"offset": 0,
"factor": 1,
"uom": 0,
"type": 6,
"is_system": true
}
],
"masked_entities": []
}
}, },
{ "NTP": {
"type": "entities", "enabled": true,
"Entities": { "server": "time.google.com",
"entities": [] "tz_label": "Europe/Amsterdam",
} "tz_format": "CET-1CEST,M3.5.0,M10.5.0/3"
}, },
{ "Security": {
"type": "modules", "jwt_secret": "ems-esp-neo",
"Modules": { "users": [
"modules": [] {
} "username": "admin",
"password": "admin",
"admin": true
},
{
"username": "guest",
"password": "guest",
"admin": false
}
]
}, },
{ "Settings": {
"type": "customSupport", "board_profile": "S3",
"Support": { "locale": "en",
"html": [ "tx_mode": 1,
"This product is installed and managed by:", "ems_bus_id": 11,
"", "boiler_heatingoff": false,
"<b>Bosch Installer Example</b>", "hide_led": true,
"", "telnet_enabled": true,
"Nefit Road 12", "notoken_api": false,
"1234 AB Amsterdam", "analog_enabled": true,
"Phone: +31 123 456 789", "fahrenheit": false,
"email: support@boschinstaller.nl", "bool_format": 1,
"", "bool_dashboard": 1,
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer." "enum_format": 1
],
"img_url": "https://emsesp.org/media/images/designer.png"
}
} }
] }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@ telegram_type_id,name,is_fetched
0x19,UBAMonitorSlow, 0x19,UBAMonitorSlow,
0x1A,UBASetPoints, 0x1A,UBASetPoints,
0x1C,UBAMaintenanceStatus, 0x1C,UBAMaintenanceStatus,
0x1E,HydrTemp, 0x1E,WM10TempMessage,
0x23,JunkersSetMixer,fetched 0x23,JunkersSetMixer,fetched
0x27,UBASettingsWW,fetched 0x27,UBASettingsWW,fetched
0x28,WeatherComp,fetched 0x28,WeatherComp,fetched
@@ -72,12 +72,11 @@ telegram_type_id,name,is_fetched
0xE6,UBAParametersPlus,fetched 0xE6,UBAParametersPlus,fetched
0xE9,UBAMonitorWWPlus, 0xE9,UBAMonitorWWPlus,
0xEA,UBAParameterWWPlus,fetched 0xEA,UBAParameterWWPlus,fetched
0xEB,PumpKick,fetched
0x0101,ISM1Set,fetched 0x0101,ISM1Set,fetched
0x0103,ISM1StatusMessage,fetched 0x0103,ISM1StatusMessage,fetched
0x0104,ISM2StatusMessage, 0x0104,ISM2StatusMessage,
0x010C,IPMStatusMessage, 0x010C,IPMStatusMessage,
0x011E,IPMTempMessage, 0x011E,JunkersDisp,fetched
0x012E,HPEnergy1, 0x012E,HPEnergy1,
0x013B,HPEnergy2, 0x013B,HPEnergy2,
0x0165,JunkersSet, 0x0165,JunkersSet,
@@ -112,8 +111,8 @@ telegram_type_id,name,is_fetched
0x02A0,RC300Curves, 0x02A0,RC300Curves,
0x02A1,RC300Curves, 0x02A1,RC300Curves,
0x02A2,RC300Curves, 0x02A2,RC300Curves,
0x02A5,RC300Monitor,fetched 0x02A5,RC300Monitor,
0x02A6,CRFMonitor, 0x02A6,RC300Monitor,
0x02A7,RC300Monitor, 0x02A7,RC300Monitor,
0x02A8,CRFMonitor, 0x02A8,CRFMonitor,
0x02A9,RC300Monitor, 0x02A9,RC300Monitor,
@@ -198,7 +197,7 @@ telegram_type_id,name,is_fetched
0x04A2,HpInput,fetched 0x04A2,HpInput,fetched
0x04A5,HPFan,fetched 0x04A5,HPFan,fetched
0x04A7,HPPowerLimit,fetched 0x04A7,HPPowerLimit,fetched
0x04AA,HPPower, 0x04AA,HPPower2,fetched
0x04AE,HPEnergy,fetched 0x04AE,HPEnergy,fetched
0x04AF,HPMeters,fetched 0x04AF,HPMeters,fetched
0x055C,VentilationSet,fetched 0x055C,VentilationSet,fetched
1 telegram_type_id name is_fetched
13 0x19 UBAMonitorSlow
14 0x1A UBASetPoints
15 0x1C UBAMaintenanceStatus
16 0x1E HydrTemp WM10TempMessage
17 0x23 JunkersSetMixer fetched
18 0x27 UBASettingsWW fetched
19 0x28 WeatherComp fetched
72 0xE6 UBAParametersPlus fetched
73 0xE9 UBAMonitorWWPlus
74 0xEA UBAParameterWWPlus fetched
0xEB PumpKick fetched
75 0x0101 ISM1Set fetched
76 0x0103 ISM1StatusMessage fetched
77 0x0104 ISM2StatusMessage
78 0x010C IPMStatusMessage
79 0x011E IPMTempMessage JunkersDisp fetched
80 0x012E HPEnergy1
81 0x013B HPEnergy2
82 0x0165 JunkersSet
111 0x02A0 RC300Curves
112 0x02A1 RC300Curves
113 0x02A2 RC300Curves
114 0x02A5 RC300Monitor fetched
115 0x02A6 CRFMonitor RC300Monitor
116 0x02A7 RC300Monitor
117 0x02A8 CRFMonitor
118 0x02A9 RC300Monitor
197 0x04A2 HpInput fetched
198 0x04A5 HPFan fetched
199 0x04A7 HPPowerLimit fetched
200 0x04AA HPPower HPPower2 fetched
201 0x04AE HPEnergy fetched
202 0x04AF HPMeters fetched
203 0x055C VentilationSet fetched

View File

@@ -1,5 +1,5 @@
{ {
"adapter": "react", "adapter": "react",
"baseLocale": "pl", "baseLocale": "pl",
"$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json" "$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
} }

View File

@@ -1,10 +1,9 @@
// @ts-check // @ts-check
import eslint from '@eslint/js'; import eslint from '@eslint/js';
import prettierConfig from 'eslint-config-prettier'; import prettierConfig from 'eslint-config-prettier';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint'; import tseslint from 'typescript-eslint';
export default defineConfig( export default tseslint.config(
eslint.configs.recommended, eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.recommendedTypeChecked,
prettierConfig, prettierConfig,

View File

@@ -1,6 +1,6 @@
{ {
"name": "EMS-ESP", "name": "EMS-ESP",
"version": "3.8.2", "version": "3.8.0",
"description": "EMS-ESP WebUI", "description": "EMS-ESP WebUI",
"homepage": "https://emsesp.org", "homepage": "https://emsesp.org",
"author": "proddy, emsesp.org", "author": "proddy, emsesp.org",
@@ -26,45 +26,46 @@
"@alova/adapter-xhr": "2.3.1", "@alova/adapter-xhr": "2.3.1",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.0.0", "@mui/icons-material": "^7.3.7",
"@mui/material": "^9.0.0", "@mui/material": "^7.3.7",
"@preact/compat": "^18.3.2", "@preact/compat": "^18.3.1",
"@table-library/react-table-library": "4.1.15", "@table-library/react-table-library": "4.1.15",
"alova": "^3.5.1", "alova": "3.4.1",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"etag": "^1.8.1", "etag": "^1.8.1",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"magic-string": "^0.30.21", "magic-string": "^0.30.21",
"mime-types": "^3.0.2", "mime-types": "^3.0.2",
"preact": "^10.29.1", "preact": "^10.28.2",
"react": "^19.2.5", "react": "^19.2.3",
"react-dom": "^19.2.5", "react-dom": "^19.2.3",
"react-icons": "^5.6.0", "react-icons": "^5.5.0",
"react-router": "^7.14.1", "react-router": "^7.12.0",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"typesafe-i18n": "^5.27.1", "typesafe-i18n": "^5.26.2",
"typescript": "^6.0.3" "typescript": "^5.9.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.29.0", "@babel/core": "^7.28.5",
"@eslint/js": "^10.0.1", "@eslint/js": "^9.39.2",
"@preact/compat": "^18.3.2", "@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.5", "@preact/preset-vite": "^2.10.2",
"@trivago/prettier-plugin-sort-imports": "^6.0.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.6.0", "@types/node": "^25.0.6",
"@types/react": "^19.2.14", "@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"axe-core": "^4.11.3", "axe-core": "^4.11.1",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"eslint": "^10.2.0", "eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.3", "prettier": "^3.7.4",
"rollup-plugin-visualizer": "^7.0.1", "rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.46.1", "terser": "^5.44.1",
"typescript-eslint": "^8.58.2", "typescript-eslint": "^8.52.0",
"vite": "^8.0.8", "vite": "^7.3.1",
"vite-plugin-imagemin": "^0.6.1" "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.0.4"
}, },
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" "packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
} }

2466
interface/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@ import { toast } from 'react-toastify';
import ForwardIcon from '@mui/icons-material/Forward'; import ForwardIcon from '@mui/icons-material/Forward';
import { Box, Button, Paper, Typography } from '@mui/material'; import { Box, Button, Paper, Typography } from '@mui/material';
import type { Theme } from '@mui/material/styles';
import * as AuthenticationApi from 'components/routing/authentication'; import * as AuthenticationApi from 'components/routing/authentication';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
@@ -37,7 +36,7 @@ const SignIn = memo(() => {
{ {
immediate: false immediate: false
} }
).onSuccess((response: { data: { access_token: string } }) => { ).onSuccess((response) => {
if (response.data) { if (response.data) {
authenticationContext.signIn(response.data.access_token); authenticationContext.signIn(response.data.access_token);
} }
@@ -79,6 +78,7 @@ const SignIn = memo(() => {
} }
}, [signInRequest, signIn, LL]); }, [signInRequest, signIn, LL]);
// Memoize callback to prevent recreation on every render
const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]); const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]);
// get rid of scrollbar // get rid of scrollbar
@@ -92,15 +92,13 @@ const SignIn = memo(() => {
return ( return (
<Box <Box
sx={(theme: Theme) => ({ display="flex"
display: 'flex', height="100vh"
height: '100vh', margin="auto"
margin: 'auto', padding={2}
padding: 2, justifyContent="center"
justifyContent: 'center', flexDirection="column"
flexDirection: 'column', maxWidth={(theme) => theme.breakpoints.values.sm}
maxWidth: theme.breakpoints.values.sm
})}
> >
<Paper <Paper
sx={(theme) => ({ sx={(theme) => ({
@@ -113,18 +111,16 @@ const SignIn = memo(() => {
width: '100%' width: '100%'
})} })}
> >
<Typography sx={{ mb: 1 }} variant="h4"> <Typography mb={1} variant="h4">
{PROJECT_NAME} {PROJECT_NAME}
</Typography> </Typography>
<LanguageSelector /> <LanguageSelector />
<Box <Box
sx={{ mt={1}
mt: 1, display="flex"
display: 'flex', flexDirection="column"
flexDirection: 'column', gap={1}
gap: 1, alignItems="center"
alignItems: 'center'
}}
> >
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors || {}} fieldErrors={fieldErrors || {}}

View File

@@ -310,15 +310,13 @@ const CustomEntities = () => {
/> />
)} )}
</Cell> </Cell>
<Cell>{ei.ram > 0 ? '' : showHex(ei.device_id as number, 2)}</Cell>
<Cell>{ei.ram > 0 ? '' : showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.ram > 0 ? '' : ei.offset}</Cell>
<Cell> <Cell>
{ei.ram === 1 {ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}
? 'RAM' </Cell>
: ei.ram === 2 <Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
? 'NVS' <Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
: DeviceValueTypeNames[ei.value_type]} <Cell>
{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}
</Cell> </Cell>
<Cell>{formatValue(ei.value, ei.uom)}</Cell> <Cell>{formatValue(ei.value, ei.uom)}</Cell>
</Row> </Row>
@@ -343,9 +341,9 @@ const CustomEntities = () => {
return ( return (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<Typography sx={{ mb: 2 }} color="warning" variant="body1"> <Box mb={2} color="warning.main">
{LL.ENTITIES_HELP_1()}. <Typography variant="body1">{LL.ENTITIES_HELP_1()}.</Typography>
</Typography> </Box>
{renderEntity()} {renderEntity()}
@@ -361,8 +359,8 @@ const CustomEntities = () => {
/> />
)} )}
<Box sx={{ mt: 2, display: 'flex', flexWrap: 'wrap' }}> <Box mt={2} display="flex" flexWrap="wrap">
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
{numChanges > 0 && ( {numChanges > 0 && (
<ButtonRow> <ButtonRow>
<Button <Button
@@ -384,7 +382,7 @@ const CustomEntities = () => {
</ButtonRow> </ButtonRow>
)} )}
</Box> </Box>
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}> <Box flexWrap="nowrap" whiteSpace="nowrap">
<Button <Button
startIcon={<AddIcon />} startIcon={<AddIcon />}
variant="outlined" variant="outlined"

View File

@@ -7,7 +7,7 @@ import DoneIcon from '@mui/icons-material/Done';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined'; import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined'; import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import { import {
Box, Box,
Button, Button,
@@ -178,7 +178,7 @@ const CustomEntitiesDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
</Grid> </Grid>
<Grid sx={{ mt: 3 }}> <Grid mt={3}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -205,10 +205,9 @@ const CustomEntitiesDialog = ({
> >
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem> <MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem> <MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
<MenuItem value={2}>NVS-{LL.VALUE(1)}</MenuItem>
</TextField> </TextField>
</Grid> </Grid>
{editItem.ram > 0 && ( {editItem.ram === 1 && (
<> <>
<Grid> <Grid>
<TextField <TextField
@@ -238,7 +237,7 @@ const CustomEntitiesDialog = ({
)} )}
{editItem.ram === 0 && ( {editItem.ram === 0 && (
<> <>
<Grid sx={{ mt: 3 }}> <Grid mt={3}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -404,7 +403,7 @@ const CustomEntitiesDialog = ({
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
variant="outlined" variant="outlined"

View File

@@ -111,14 +111,13 @@ const Customizations = () => {
const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] = const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] =
useState<string>(''); // needed for API URL useState<string>(''); // needed for API URL
const [selectedDeviceName, setSelectedDeviceName] = useState<string>(''); const [selectedDeviceName, setSelectedDeviceName] = useState<string>('');
const [selectedDeviceBrand, setSelectedDeviceBrand] = useState<string>('');
const { send: sendResetCustomizations } = useRequest(resetCustomizations(), { const { send: sendResetCustomizations } = useRequest(resetCustomizations(), {
immediate: false immediate: false
}); });
const { send: sendDeviceName } = useRequest( const { send: sendDeviceName } = useRequest(
(data: { id: number; name: string; brand: string }) => writeDeviceName(data), (data: { id: number; name: string }) => writeDeviceName(data),
{ {
immediate: false immediate: false
} }
@@ -268,7 +267,6 @@ const Customizations = () => {
if (device) { if (device) {
setSelectedDeviceTypeNameURL(device.url || ''); setSelectedDeviceTypeNameURL(device.url || '');
setSelectedDeviceName(device.n); setSelectedDeviceName(device.n);
setSelectedDeviceBrand(device.b);
} }
setNumChanges(0); setNumChanges(0);
setRestartNeeded(false); setRestartNeeded(false);
@@ -444,11 +442,7 @@ const Customizations = () => {
}, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]); }, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]);
const renameDevice = useCallback(async () => { const renameDevice = useCallback(async () => {
await sendDeviceName({ await sendDeviceName({ id: selectedDevice, name: selectedDeviceName })
id: selectedDevice,
name: selectedDeviceName,
brand: selectedDeviceBrand
})
.then(() => { .then(() => {
toast.success(LL.UPDATED_OF(LL.NAME(1))); toast.success(LL.UPDATED_OF(LL.NAME(1)));
}) })
@@ -459,42 +453,24 @@ const Customizations = () => {
setRename(false); setRename(false);
await fetchCoreData(); await fetchCoreData();
}); });
}, [ }, [selectedDevice, selectedDeviceName, sendDeviceName, LL, fetchCoreData]);
selectedDevice,
selectedDeviceName,
selectedDeviceBrand,
sendDeviceName,
LL,
fetchCoreData
]);
const renderDeviceList = () => ( const renderDeviceList = () => (
<> <>
<Typography sx={{ mb: 1 }} color="warning" variant="body1"> <Box mb={1} color="warning.main">
{LL.CUSTOMIZATIONS_HELP_1()}. <Typography variant="body1">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
</Typography> </Box>
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 2 }}> <Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
{rename ? ( {rename ? (
<> <TextField
<TextField name="device"
name="device" label={LL.EMS_DEVICE()}
label={LL.EMS_DEVICE()} fullWidth
style={{ minWidth: '48%' }} variant="outlined"
variant="outlined" value={selectedDeviceName}
value={selectedDeviceName} onChange={(e) => setSelectedDeviceName(e.target.value)}
onChange={(e) => setSelectedDeviceName(e.target.value)} margin="normal"
margin="normal" />
/>
<TextField
name="brand"
label={LL.BRAND()}
style={{ minWidth: '48%' }}
variant="outlined"
value={selectedDeviceBrand}
onChange={(e) => setSelectedDeviceBrand(e.target.value)}
margin="normal"
/>
</>
) : ( ) : (
<TextField <TextField
name="device" name="device"
@@ -570,22 +546,27 @@ const Customizations = () => {
const renderDeviceData = () => { const renderDeviceData = () => {
return ( return (
<> <>
<Typography sx={{ mt: 1, mb: 1 }} color="warning" variant="body2"> <Box color="warning.main">
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()} <Typography variant="body2" mt={1} mb={1}>
&nbsp;&nbsp; <OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()} &nbsp;&nbsp;
&nbsp;&nbsp; <OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
<OptionIcon type="api_mqtt_exclude" isSet={true} />= &nbsp;&nbsp;
{LL.CUSTOMIZATIONS_HELP_4()}&nbsp;&nbsp; <OptionIcon type="api_mqtt_exclude" isSet={true} />=
<OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()} {LL.CUSTOMIZATIONS_HELP_4()}&nbsp;&nbsp;
&nbsp;&nbsp; <OptionIcon type="web_exclude" isSet={true} />=
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()} {LL.CUSTOMIZATIONS_HELP_5()}&nbsp;&nbsp;
</Typography> <OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
</Typography>
</Box>
<Grid <Grid
container container
mb={1}
mt={0}
spacing={2} spacing={2}
direction="row" direction="row"
sx={{ mb: 1, mt: 0, justifyContent: 'flex-start', alignItems: 'center' }} justifyContent="flex-start"
alignItems="center"
> >
<Grid> <Grid>
<TextField <TextField
@@ -774,8 +755,8 @@ const Customizations = () => {
</Button> </Button>
</MessageBox> </MessageBox>
) : ( ) : (
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}> <Box display="flex" flexWrap="wrap">
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button

View File

@@ -37,7 +37,7 @@ interface LabelValueProps {
const LabelValue = memo(({ label, value }: LabelValueProps) => ( const LabelValue = memo(({ label, value }: LabelValueProps) => (
<Grid container direction="row"> <Grid container direction="row">
<Typography variant="body2" color="warning"> <Typography variant="body2" color="warning.main">
{label}:&nbsp; {label}:&nbsp;
</Typography> </Typography>
<Typography variant="body2">{value}</Typography> <Typography variant="body2">{value}</Typography>
@@ -131,7 +131,7 @@ const CustomizationsDialog = ({
/> />
<LabelValue label={LL.WRITEABLE()} value={writeableIcon} /> <LabelValue label={LL.WRITEABLE()} value={writeableIcon} />
<Box sx={{ mt: 1, mb: 2 }}> <Box mt={1} mb={2}>
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} /> <EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
</Box> </Box>
@@ -172,7 +172,7 @@ const CustomizationsDialog = ({
</Grid> </Grid>
{error && ( {error && (
<Typography sx={{ mt: 2 }} variant="body2" color="error"> <Typography variant="body2" color="error" mt={2}>
Error: Check min and max values Error: Check min and max values
</Typography> </Typography>
)} )}

View File

@@ -6,7 +6,7 @@ import { toast } from 'react-toastify';
import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import HelpOutlineIcon from '@mui/icons-material/HelpOutlined'; import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess'; import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore'; import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
import { import {
@@ -262,8 +262,12 @@ const Dashboard = memo(() => {
return ( return (
<> <>
{!data.connected && (
<MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
)}
{data.connected && data.nodes.length > 0 && !hasFavEntities && ( {data.connected && data.nodes.length > 0 && !hasFavEntities && (
<MessageBox sx={{ mb: 2 }} level="warning"> <MessageBox mb={2} level="warning">
<Typography> <Typography>
{LL.NO_DATA_1()}&nbsp; {LL.NO_DATA_1()}&nbsp;
<Link to="/customizations" style={{ color: 'white' }}> <Link to="/customizations" style={{ color: 'white' }}>
@@ -280,12 +284,10 @@ const Dashboard = memo(() => {
)} )}
<Box <Box
sx={{ display="flex"
display: 'flex', justifyContent="flex-end"
justifyContent: 'flex-end', flexWrap="nowrap"
flexWrap: 'nowrap', whiteSpace="nowrap"
whiteSpace: 'nowrap'
}}
> >
<ToggleButtonGroup <ToggleButtonGroup
size="small" size="small"
@@ -308,7 +310,7 @@ const Dashboard = memo(() => {
</Box> </Box>
{data.nodes.length > 0 ? ( {data.nodes.length > 0 ? (
<Box sx={{ mt: 1, justifyContent: 'center', flexDirection: 'column' }}> <Box mt={1} justifyContent="center" flexDirection="column">
<IconContext.Provider <IconContext.Provider
value={{ value={{
color: 'lightblue', color: 'lightblue',
@@ -375,8 +377,13 @@ const Dashboard = memo(() => {
</IconContext.Provider> </IconContext.Provider>
</Box> </Box>
) : ( ) : (
<Box sx={{ display: 'flex' }}> <Box
<Typography sx={{ mt: 1 }} color="warning" variant="body1"> display="flex"
// justifyContent="flex-end"
// flexWrap="nowrap"
// whiteSpace="nowrap"
>
<Typography mt={1} color="warning.main" variant="body1">
no data no data
</Typography> </Typography>
<Tooltip title={LL.DASHBOARD_1()}> <Tooltip title={LL.DASHBOARD_1()}>

View File

@@ -1,5 +1,4 @@
import { memo } from 'react'; import { memo } from 'react';
import type { IconType } from 'react-icons';
import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai'; import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai';
import { CgSmartHomeBoiler } from 'react-icons/cg'; import { CgSmartHomeBoiler } from 'react-icons/cg';
import { FaSolarPanel } from 'react-icons/fa'; import { FaSolarPanel } from 'react-icons/fa';
@@ -16,9 +15,14 @@ import { PiFan, PiGauge } from 'react-icons/pi';
import { TiFlowSwitch, TiThermometer } from 'react-icons/ti'; import { TiFlowSwitch, TiThermometer } from 'react-icons/ti';
import { VscVmConnect } from 'react-icons/vsc'; import { VscVmConnect } from 'react-icons/vsc';
import type { SvgIconProps } from '@mui/material';
import { DeviceType } from './types'; import { DeviceType } from './types';
const deviceIconLookup: Record<DeviceType, IconType | null> = { const deviceIconLookup: Record<
DeviceType,
React.ComponentType<SvgIconProps> | null
> = {
[DeviceType.TEMPERATURESENSOR]: TiThermometer, [DeviceType.TEMPERATURESENSOR]: TiThermometer,
[DeviceType.ANALOGSENSOR]: PiGauge, [DeviceType.ANALOGSENSOR]: PiGauge,
[DeviceType.BOILER]: CgSmartHomeBoiler, [DeviceType.BOILER]: CgSmartHomeBoiler,

View File

@@ -8,7 +8,7 @@ import {
useState useState
} from 'react'; } from 'react';
import { IconContext } from 'react-icons'; import { IconContext } from 'react-icons';
import { Link, useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined'; import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
@@ -534,19 +534,9 @@ const Devices = memo(() => {
const renderCoreData = () => ( const renderCoreData = () => (
<> <>
{!coreData.connected ? ( {!coreData.connected ? (
<MessageBox level="error" message={LL.EMS_BUS_WARNING() + '.'}> <MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
&nbsp;(
<Link
target="_blank"
to="https://docs.emsesp.org/Troubleshooting#ems-bus-is-not-connecting"
style={{ color: 'white' }}
>
{LL.ONLINE_HELP()}
</Link>
)
</MessageBox>
) : ( ) : (
<Box sx={{ justifyContent: 'center', flexDirection: 'column' }}> <Box justifyContent="center" flexDirection="column">
<IconContext.Provider <IconContext.Provider
value={{ value={{
color: 'lightblue', color: 'lightblue',
@@ -670,12 +660,12 @@ const Devices = memo(() => {
}} }}
> >
<Box sx={{ p: 1 }}> <Box sx={{ p: 1 }}>
<Grid container sx={{ justifyContent: 'space-between' }}> <Grid container justifyContent="space-between">
<Typography noWrap variant="subtitle1" color="warning"> <Typography noWrap variant="subtitle1" color="warning.main">
{deviceInfo.n}&nbsp;( {deviceInfo.n}&nbsp;(
{deviceInfo.tn}) {deviceInfo.tn})
</Typography> </Typography>
<Grid sx={{ justifyContent: 'flex-end' }}> <Grid justifyContent="flex-end">
<ButtonTooltip title={LL.CLOSE()}> <ButtonTooltip title={LL.CLOSE()}>
<IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}> <IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}>
<HighlightOffIcon color="primary" sx={{ fontSize: 18 }} /> <HighlightOffIcon color="primary" sx={{ fontSize: 18 }} />

View File

@@ -128,9 +128,9 @@ const DevicesDialog = ({
<Dialog sx={dialogStyle} open={open} onClose={onClose}> <Dialog sx={dialogStyle} open={open} onClose={onClose}>
<DialogTitle>{dialogTitle}</DialogTitle> <DialogTitle>{dialogTitle}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography sx={{ mb: 2 }} color="warning" variant="body2"> <Box color="warning.main" mb={2}>
{editItem.id.slice(2)} <Typography variant="body2">{editItem.id.slice(2)}</Typography>
</Typography> </Box>
<Grid container> <Grid container>
<Grid size={12}> <Grid size={12}>
{editItem.l ? ( {editItem.l ? (

View File

@@ -11,7 +11,6 @@ import {
Box, Box,
Button, Button,
Divider, Divider,
Grid,
Link, Link,
List, List,
ListItem, ListItem,
@@ -43,7 +42,7 @@ interface CustomSupport {
html: string | null; html: string | null;
} }
const DEFAULT_IMAGE_URL = 'https://emsesp.org/media/images/installer.jpeg'; const DEFAULT_IMAGE_URL = 'https://emsesp.org/_media/images/installer.jpeg';
const SUPPORT_BOX_STYLES: SxProps<Theme> = { const SUPPORT_BOX_STYLES: SxProps<Theme> = {
borderRadius: 3, borderRadius: 3,
@@ -72,6 +71,7 @@ const HelpComponent = () => {
}); });
const [imgError, setImgError] = useState<boolean>(false); const [imgError, setImgError] = useState<boolean>(false);
// Memoize the request method to prevent re-creation on every render
const getCustomSupportMethod = useMemo( const getCustomSupportMethod = useMemo(
() => callAction({ action: 'getCustomSupport' }), () => callAction({ action: 'getCustomSupport' }),
[] []
@@ -120,7 +120,7 @@ const HelpComponent = () => {
label: () => LL.HELP_INFORMATION_1() label: () => LL.HELP_INFORMATION_1()
}, },
{ {
href: 'https://discord.gg/GP9DPSgeJq', href: 'https://discord.gg/3J3GgnzpyT',
icon: <CommentIcon />, icon: <CommentIcon />,
label: () => LL.HELP_INFORMATION_2() label: () => LL.HELP_INFORMATION_2()
}, },
@@ -146,9 +146,11 @@ const HelpComponent = () => {
<SectionContent> <SectionContent>
{customSupport.html && ( {customSupport.html && (
<Stack <Stack
padding={1}
mb={2}
direction="row" direction="row"
divider={<Divider orientation="vertical" flexItem />} divider={<Divider orientation="vertical" flexItem />}
sx={{ padding: 1, mb: 2, ...SUPPORT_BOX_STYLES }} sx={SUPPORT_BOX_STYLES}
> >
<Typography variant="subtitle1"> <Typography variant="subtitle1">
<div dangerouslySetInnerHTML={{ __html: customSupport.html }} /> <div dangerouslySetInnerHTML={{ __html: customSupport.html }} />
@@ -183,9 +185,9 @@ const HelpComponent = () => {
</List> </List>
)} )}
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}> <Box p={2} color="warning.main">
<Typography sx={{ mb: 1 }} color="warning" variant="body1"> <Typography mb={1} variant="body1">
{LL.HELP_INFORMATION_4()}: {LL.HELP_INFORMATION_4()}.
</Typography> </Typography>
<Button <Button
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
@@ -195,11 +197,11 @@ const HelpComponent = () => {
> >
{LL.SUPPORT_INFORMATION(0)} {LL.SUPPORT_INFORMATION(0)}
</Button> </Button>
</Grid> </Box>
<Divider sx={{ mt: 4 }} /> <Divider sx={{ mt: 4 }} />
<Typography color="white" variant="subtitle1" align="center" sx={{ mt: 1 }}> <Typography color="white" variant="subtitle1" align="center" mt={1}>
&copy;&nbsp; &copy;&nbsp;
<Link <Link
target="_blank" target="_blank"

View File

@@ -186,9 +186,9 @@ const Modules = () => {
return ( return (
<> <>
<Typography sx={{ mb: 2 }} color="warning" variant="body1"> <Box mb={2} color="warning.main">
{LL.MODULES_DESCRIPTION()}. <Typography variant="body1">{LL.MODULES_DESCRIPTION()}.</Typography>
</Typography> </Box>
<Table <Table
data={{ nodes: modules }} data={{ nodes: modules }}
theme={modules_theme} theme={modules_theme}
@@ -236,8 +236,8 @@ const Modules = () => {
)} )}
</Table> </Table>
<Box sx={{ mt: 1, display: 'flex', flexWrap: 'wrap' }}> <Box mt={1} display="flex" flexWrap="wrap">
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button

View File

@@ -79,7 +79,7 @@ const ModulesDialog = ({
label="Enabled" label="Enabled"
/> />
</Grid> </Grid>
<Box sx={{ mt: 2, mb: 1 }}> <Box mt={2} mb={1}>
<TextField <TextField
name="license" name="license"
label="License Key" label="License Key"

View File

@@ -2,12 +2,12 @@ import { memo } from 'react';
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined'; import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutlined'; import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined'; import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined'; import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
import StarIcon from '@mui/icons-material/Star'; import StarIcon from '@mui/icons-material/Star';
import StarOutlineIcon from '@mui/icons-material/StarOutlined'; import StarOutlineIcon from '@mui/icons-material/StarOutline';
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import type { SvgIconProps } from '@mui/material'; import type { SvgIconProps } from '@mui/material';

View File

@@ -358,9 +358,9 @@ const Scheduler = () => {
return ( return (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<Typography sx={{ mb: 2 }} color="warning" variant="body1"> <Box mb={2} color="warning.main">
{LL.SCHEDULER_HELP_1()}. <Typography variant="body1">{LL.SCHEDULER_HELP_1()}.</Typography>
</Typography> </Box>
{renderSchedule()} {renderSchedule()}
{selectedScheduleItem && ( {selectedScheduleItem && (
@@ -375,8 +375,8 @@ const Scheduler = () => {
/> />
)} )}
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}> <Box display="flex" flexWrap="wrap">
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button
@@ -398,7 +398,7 @@ const Scheduler = () => {
</ButtonRow> </ButtonRow>
)} )}
</Box> </Box>
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}> <Box flexWrap="nowrap" whiteSpace="nowrap">
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<AddIcon />} startIcon={<AddIcon />}

View File

@@ -4,7 +4,7 @@ import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import { import {
Box, Box,
Button, Button,
@@ -338,13 +338,11 @@ const SchedulerDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
{isTimerSchedule && ( {isTimerSchedule && (
<Typography <Box color="warning.main" ml={2} mt={4}>
sx={{ ml: 2, mt: 4 }} <Typography variant="body2">
color="warning" {LL.SCHEDULER_HELP_2()}
variant="body2" </Typography>
> </Box>
{LL.SCHEDULER_HELP_2()}
</Typography>
)} )}
</> </>
) : ( ) : (
@@ -393,7 +391,7 @@ const SchedulerDialog = ({
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box sx={{ flexGrow: 1 }}> <Box flexGrow={1}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
variant="outlined" variant="outlined"

View File

@@ -348,7 +348,7 @@ const Sensors = () => {
const addAnalogSensor = useCallback(() => { const addAnalogSensor = useCallback(() => {
if (firstAvailableGPIO.current === undefined) { if (firstAvailableGPIO.current === undefined) {
toast.error(LL.NO_GPIO()); toast.error('No available GPIO found');
return; return;
} }
setCreating(true); setCreating(true);
@@ -591,14 +591,7 @@ const Sensors = () => {
/> />
)} )}
{sensorData?.analog_enabled === true && me.admin && ( {sensorData?.analog_enabled === true && me.admin && (
<Box <Box mt={2} display="flex" flexWrap="wrap" justifyContent="flex-end">
sx={{
mt: 2,
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'flex-end'
}}
>
<Button <Button
variant="outlined" variant="outlined"
color="primary" color="primary"

View File

@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { import {
Box, Box,
@@ -479,7 +479,7 @@ const SensorsAnalogDialog = ({
)} )}
</Grid> </Grid>
{fieldErrors && Object.keys(fieldErrors).length > 0 && ( {fieldErrors && Object.keys(fieldErrors).length > 0 && (
<Box sx={{ mt: 1 }}> <Box mt={1}>
{Object.values(fieldErrors).map((errArr, idx) => {Object.values(fieldErrors).map((errArr, idx) =>
Array.isArray(errArr) Array.isArray(errArr)
? errArr.map((err, j) => ( ? errArr.map((err, j) => (
@@ -487,7 +487,7 @@ const SensorsAnalogDialog = ({
key={`${idx}-${j}`} key={`${idx}-${j}`}
color="error" color="error"
variant="caption" variant="caption"
sx={{ display: 'block' }} display="block"
> >
{err.message} {err.message}
</Typography> </Typography>
@@ -498,7 +498,7 @@ const SensorsAnalogDialog = ({
)} )}
{editItem.s && ( {editItem.s && (
<Grid> <Grid>
<Typography sx={{ mt: 1 }} color="warning" variant="body2"> <Typography mt={1} color="warning.main" variant="body2">
<WarningIcon <WarningIcon
fontSize="small" fontSize="small"
sx={{ mr: 1, verticalAlign: 'middle' }} sx={{ mr: 1, verticalAlign: 'middle' }}
@@ -511,7 +511,7 @@ const SensorsAnalogDialog = ({
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box sx={{ flexGrow: 1, '& button': { mt: 0 } }}> <Box flexGrow={1} sx={{ '& button': { mt: 0 } }}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
disabled={editItem.s} disabled={editItem.s}

View File

@@ -4,6 +4,7 @@ import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { import {
Box,
Button, Button,
Dialog, Dialog,
DialogActions, DialogActions,
@@ -110,9 +111,11 @@ const SensorsTemperatureDialog = ({
<Dialog sx={dialogStyle} open={open} onClose={handleClose}> <Dialog sx={dialogStyle} open={open} onClose={handleClose}>
<DialogTitle>{dialogTitle}</DialogTitle> <DialogTitle>{dialogTitle}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography sx={{ mb: 2 }} color="warning" variant="body2"> <Box color="warning.main" mb={2}>
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id} <Typography variant="body2">
</Typography> {LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
</Typography>
</Box>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid> <Grid>
<ValidatedTextField <ValidatedTextField
@@ -139,7 +142,7 @@ const SensorsTemperatureDialog = ({
</Grid> </Grid>
{editItem.s && ( {editItem.s && (
<Grid> <Grid>
<Typography sx={{ mt: 1 }} color="warning" variant="body2"> <Typography mt={1} color="warning.main" variant="body2">
<WarningIcon <WarningIcon
fontSize="small" fontSize="small"
sx={{ mr: 1, verticalAlign: 'middle' }} sx={{ mr: 1, verticalAlign: 'middle' }}

View File

@@ -41,12 +41,8 @@ const UserProfileComponent = () => {
/> />
</ListItem> </ListItem>
</List> </List>
<Box sx={{ mt: 2, mb: 2, display: 'flex', alignItems: 'center' }}> <Box mt={2} mb={2} display="flex" alignItems="center">
<Typography <Typography mr={2} variant="body1" align="center">
sx={{ mr: 2, textAlign: 'center' }}
color="warning"
variant="body1"
>
{LL.LANGUAGE()}: {LL.LANGUAGE()}:
</Typography> </Typography>
<LanguageSelector /> <LanguageSelector />

View File

@@ -43,16 +43,6 @@ export interface Settings {
modbus_port: number; modbus_port: number;
modbus_max_clients: number; modbus_max_clients: number;
modbus_timeout: number; modbus_timeout: number;
email_enabled: boolean;
email_ssl?: boolean;
email_starttls?: boolean;
email_server: string;
email_port: number;
email_login: string;
email_pass: string;
email_sender: string;
email_recp: string;
email_subject: string;
developer_mode: boolean; developer_mode: boolean;
} }

View File

@@ -28,7 +28,6 @@ import {
FormLoader, FormLoader,
MessageBox, MessageBox,
SectionContent, SectionContent,
ValidatedPasswordField,
ValidatedTextField, ValidatedTextField,
useLayoutTitle useLayoutTitle
} from 'components'; } from 'components';
@@ -352,156 +351,6 @@ const ApplicationSettings = () => {
</Grid> </Grid>
</Grid> </Grid>
)} )}
<Typography color="secondary">eMail</Typography>
<BlockFormControlLabel
control={
<Checkbox
checked={data.email_enabled}
onChange={updateFormValue}
name="email_enabled"
disabled={!hardwareData.psram}
/>
}
label={
<Typography color={!hardwareData.psram ? 'grey' : 'default'}>
Enable eMail notification
{!hardwareData.psram && (
<Typography variant="caption">
&nbsp; &#40;{LL.IS_REQUIRED('PSRAM')}&#41;
</Typography>
)}
</Typography>
}
/>
{data.email_enabled && (
<>
<Grid
container
spacing={2}
direction="row"
justifyContent="flex-start"
alignItems="flex-start"
>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="email_server"
label="SMTP Server"
variant="outlined"
value={data.email_server}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
sx={{ width: '12ch' }}
name="email_port"
variant="outlined"
label="Port"
value={numberValue(data.email_port)}
type="number"
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid size={4} mt={!data.email_ssl && !data.email_starttls ? 0 : 3}>
{!data.email_starttls && (
<BlockFormControlLabel
sx={{ width: '12ch' }}
control={
<Checkbox
checked={data.email_ssl}
onChange={updateFormValue}
name="email_ssl"
disabled={
data.email_starttls || data.email_ssl === undefined
}
/>
}
label="SSL/TLS"
/>
)}
{!data.email_ssl && (
<BlockFormControlLabel
sx={{ width: '12ch' }}
control={
<Checkbox
checked={data.email_starttls}
onChange={updateFormValue}
name="email_starttls"
disabled={
data.email_ssl || data.email_starttls === undefined
}
/>
}
label="STARTTLS"
/>
)}
</Grid>
</Grid>
<Grid container spacing={2} rowSpacing={0}>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="email_login"
label="Login"
variant="outlined"
value={data.email_login}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid>
<ValidatedPasswordField
fieldErrors={fieldErrors || {}}
name="email_pass"
label="Password"
variant="outlined"
value={data.email_pass}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
</Grid>
<Grid container spacing={2} rowSpacing={0}>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="email_sender"
label="From"
variant="outlined"
value={data.email_sender}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="email_recp"
label="To"
variant="outlined"
value={data.email_recp}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid>
<ValidatedTextField
fieldErrors={fieldErrors || {}}
name="email_subject"
label="Subject"
variant="outlined"
value={data.email_subject}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
</Grid>
</>
)}
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
{LL.SENSORS()} {LL.SENSORS()}
</Typography> </Typography>
@@ -922,7 +771,7 @@ const ApplicationSettings = () => {
label={LL.REMOTE_TIMEOUT_EN()} label={LL.REMOTE_TIMEOUT_EN()}
/> />
{data.remote_timeout_en && ( {data.remote_timeout_en && (
<Box sx={{ mt: 2 }}> <Box mt={2}>
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors || {}} fieldErrors={fieldErrors || {}}
name="remote_timeout" name="remote_timeout"

View File

@@ -1,23 +1,12 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
import DownloadIcon from '@mui/icons-material/GetApp'; import DownloadIcon from '@mui/icons-material/GetApp';
import WarningIcon from '@mui/icons-material/Warning'; import { Box, Button, Grid, Typography } from '@mui/material';
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
Typography
} from '@mui/material';
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import { API, callAction } from 'api/app'; import { API, callAction } from 'api/app';
import { dialogStyle } from '@/CustomTheme';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
import type { APIcall } from 'app/main/types'; import type { APIcall } from 'app/main/types';
import SystemMonitor from 'app/status/SystemMonitor'; import SystemMonitor from 'app/status/SystemMonitor';
@@ -30,11 +19,16 @@ import {
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { saveFile } from 'utils'; import { saveFile } from 'utils';
interface DownloadButton {
key: string;
type: string;
label: string | number;
isGridButton: boolean;
}
const DownloadUpload = () => { const DownloadUpload = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [confirmBackup, setConfirmBackup] = useState<boolean>(false);
const [restarting, setRestarting] = useState<boolean>(false); const [restarting, setRestarting] = useState<boolean>(false);
const { send: sendExportData } = useRequest( const { send: sendExportData } = useRequest(
@@ -69,44 +63,40 @@ const DownloadUpload = () => {
useLayoutTitle(LL.DOWNLOAD_UPLOAD()); useLayoutTitle(LL.DOWNLOAD_UPLOAD());
const handleCloseBackupDialog = useCallback(() => { const downloadButtons: DownloadButton[] = useMemo(
setConfirmBackup(false); () => [
}, []); {
key: 'settings',
const renderBackupDialog = useMemo( type: 'settings',
() => ( label: LL.SETTINGS_OF(LL.APPLICATION()),
<Dialog isGridButton: true
sx={dialogStyle} },
open={confirmBackup} {
onClose={handleCloseBackupDialog} key: 'customizations',
> type: 'customizations',
<DialogTitle>{LL.DOWNLOAD_SYSTEM_BACKUP()}</DialogTitle> label: LL.CUSTOMIZATIONS(),
<DialogContent dividers> isGridButton: true
<WarningIcon color="warning" sx={{ fontSize: 18 }} /> },
&nbsp; {
{LL.WARNING_SYSTEM_BACKUP()} key: 'entities',
</DialogContent> type: 'entities',
<DialogActions> label: LL.CUSTOM_ENTITIES(0),
<Button isGridButton: true
startIcon={<CancelIcon />} },
variant="outlined" {
onClick={handleCloseBackupDialog} key: 'schedule',
color="secondary" type: 'schedule',
> label: LL.SCHEDULE(0),
{LL.CANCEL()} isGridButton: true
</Button> },
<Button {
startIcon={<DownloadIcon />} key: 'allvalues',
variant="outlined" type: 'allvalues',
onClick={() => handleDownload('systembackup')()} label: LL.ALLVALUES(),
color="primary" isGridButton: false
> }
{LL.DOWNLOAD(0)} ],
</Button> [LL]
</DialogActions>
</Dialog>
),
[confirmBackup, handleCloseBackupDialog, LL]
); );
const handleDownload = useCallback( const handleDownload = useCallback(
@@ -128,57 +118,58 @@ const DownloadUpload = () => {
); );
} }
const gridButtons = downloadButtons.filter((btn) => btn.isGridButton);
const standaloneButton = downloadButtons.find((btn) => !btn.isGridButton);
return ( return (
<SectionContent> <SectionContent>
{renderBackupDialog}
<Typography sx={{ pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)} {LL.DOWNLOAD(0)}
</Typography> </Typography>
<Grid <Typography mb={1} variant="body1" color="warning">
container {LL.DOWNLOAD_SETTINGS_TEXT()}.
spacing={2} </Typography>
sx={{
alignItems: 'center' <Grid container spacing={2}>
}} {gridButtons.map((button) => (
> <Grid key={button.key}>
<Typography variant="body1" color="warning"> <Button
{LL.DOWNLOAD_SETTINGS_TEXT()}: startIcon={<DownloadIcon />}
</Typography> variant="outlined"
<Button color="primary"
startIcon={<DownloadIcon />} onClick={handleDownload(button.type)}
variant="outlined" >
color="primary" {button.label}
onClick={() => setConfirmBackup(true)} </Button>
> </Grid>
{LL.DOWNLOAD_SYSTEM_BACKUP()} ))}
</Button>
</Grid> </Grid>
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}> <Typography mt={2} mb={1} variant="body1" color="warning">
<Typography variant="body1" color="warning"> {LL.DOWNLOAD_SETTINGS_TEXT2()}.
{LL.DOWNLOAD_SETTINGS_TEXT2()}: </Typography>
</Typography>
{standaloneButton && (
<Button <Button
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
variant="outlined" variant="outlined"
color="primary" color="primary"
onClick={handleDownload('allvalues')} onClick={handleDownload(standaloneButton.type)}
> >
{LL.ALLVALUES()} {standaloneButton.label}
</Button> </Button>
</Grid> )}
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
{LL.UPLOAD()} {LL.UPLOAD()}
</Typography> </Typography>
<Typography sx={{ pb: 2 }} color="warning" variant="body1"> <Box color="warning.main" sx={{ pb: 2 }}>
{LL.UPLOAD_TEXT()}: <Typography variant="body1">{LL.UPLOAD_TEXT()}.</Typography>
</Typography> </Box>
<SingleUpload doRestart={doRestart} /> <SingleUpload text={LL.UPLOAD_DRAG()} doRestart={doRestart} />
</SectionContent> </SectionContent>
); );
}; };

View File

@@ -129,7 +129,7 @@ const MqttSettings = () => {
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<> <>
<Box sx={{ display: 'flex', gap: 2, mb: 1 }}> <Box display="flex" gap={2} mb={1}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox

View File

@@ -193,9 +193,9 @@ const NTPSettings = () => {
{timeZoneItems} {timeZoneItems}
</ValidatedTextField> </ValidatedTextField>
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}> <Box display="flex" flexWrap="wrap">
{!data.enabled && !dirtyFlags.length && ( {!data.enabled && !dirtyFlags.length && (
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}> <Box flexWrap="nowrap" whiteSpace="nowrap">
<ButtonRow> <ButtonRow>
<Button <Button
onClick={openSetTime} onClick={openSetTime}
@@ -259,9 +259,9 @@ const NTPSettings = () => {
<Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}> <Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}>
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle> <DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography color="warning" variant="body2"> <Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>
{LL.SET_TIME_TEXT()} <Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography>
</Typography> </Box>
<TextField <TextField
label={LL.LOCAL_TIME(0)} label={LL.LOCAL_TIME(0)}
type="datetime-local" type="datetime-local"

View File

@@ -156,13 +156,11 @@ const Settings = () => {
<Divider /> <Divider />
<Box <Box
sx={{ mt={2}
mt: 2, display="flex"
display: 'flex', justifyContent="flex-end"
justifyContent: 'flex-end', flexWrap="nowrap"
flexWrap: 'nowrap', whiteSpace="nowrap"
whiteSpace: 'nowrap'
}}
> >
<Button <Button
startIcon={<SettingsBackupRestoreIcon />} startIcon={<SettingsBackupRestoreIcon />}

View File

@@ -54,27 +54,19 @@ const GenerateToken = ({ username, onClose }: GenerateTokenProps) => {
<DialogContent dividers> <DialogContent dividers>
{token ? ( {token ? (
<> <>
<MessageBox <MessageBox message={LL.ACCESS_TOKEN_TEXT()} level="info" my={2} />
message={LL.ACCESS_TOKEN_TEXT()} <Box mt={2} mb={2}>
level="info"
sx={{ mt: 2, mb: 2 }}
/>
<Box sx={{ mt: 2, mb: 2 }}>
<TextField <TextField
label="Token" label="Token"
multiline multiline
value={token.token} value={token.token}
fullWidth fullWidth
slotProps={{ contentEditable={false}
input: {
readOnly: true
}
}}
/> />
</Box> </Box>
</> </>
) : ( ) : (
<Box sx={{ m: 4, textAlign: 'center' }}> <Box m={4} textAlign="center">
<LinearProgress /> <LinearProgress />
<Typography variant="h6">{LL.GENERATING_TOKEN()}&hellip;</Typography> <Typography variant="h6">{LL.GENERATING_TOKEN()}&hellip;</Typography>
</Box> </Box>

View File

@@ -240,16 +240,12 @@ const ManageUsers = () => {
</Table> </Table>
{noAdminConfigured() && ( {noAdminConfigured() && (
<MessageBox <MessageBox level="warning" message={LL.USER_WARNING()} my={2} />
level="warning"
message={LL.USER_WARNING()}
sx={{ mt: 2, mb: 2 }}
/>
)} )}
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}> <Box display="flex" flexWrap="wrap">
{changed !== 0 && ( {changed !== 0 && (
<Box sx={{ flexGrow: 1, '& button': { mt: 2 } }}> <Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<CancelIcon />} startIcon={<CancelIcon />}
@@ -274,7 +270,7 @@ const ManageUsers = () => {
</ButtonRow> </ButtonRow>
</Box> </Box>
)} )}
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}> <Box flexWrap="nowrap" whiteSpace="nowrap">
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<PersonAddIcon />} startIcon={<PersonAddIcon />}

View File

@@ -38,6 +38,8 @@ import type { LogEntry, LogSettings } from 'types';
import { LogLevel } from 'types'; import { LogLevel } from 'types';
import { updateValueDirty, useRest } from 'utils'; import { updateValueDirty, useRest } from 'utils';
const MAX_LOG_ENTRIES = 1000; // Limit log entries to prevent memory issues
const TextColors: Record<LogLevel, string> = { const TextColors: Record<LogLevel, string> = {
[LogLevel.ERROR]: '#ff0000', // red [LogLevel.ERROR]: '#ff0000', // red
[LogLevel.WARNING]: '#ff0000', // red [LogLevel.WARNING]: '#ff0000', // red
@@ -198,6 +200,10 @@ const SystemLog = () => {
} }
} }
const newLog = [...log, logentry]; const newLog = [...log, logentry];
// Limit log entries to prevent memory issues - only slice when necessary
if (newLog.length > MAX_LOG_ENTRIES) {
return newLog.slice(-MAX_LOG_ENTRIES);
}
return newLog; return newLog;
}); });
}, []); }, []);
@@ -266,7 +272,7 @@ const SystemLog = () => {
return ( return (
<> <>
<Grid container spacing={2} sx={{ alignItems: 'center' }}> <Grid container spacing={2} alignItems="center">
<Grid> <Grid>
<TextField <TextField
name="level" name="level"
@@ -302,8 +308,6 @@ const SystemLog = () => {
<MenuItem value={50}>50</MenuItem> <MenuItem value={50}>50</MenuItem>
<MenuItem value={75}>75</MenuItem> <MenuItem value={75}>75</MenuItem>
<MenuItem value={100}>100</MenuItem> <MenuItem value={100}>100</MenuItem>
<MenuItem value={500}>500</MenuItem>
<MenuItem value={1000}>1000</MenuItem>
</TextField> </TextField>
</Grid> </Grid>
)} )}

View File

@@ -60,16 +60,18 @@ const SystemMonitor = () => {
const { statusMessage, isUploading, progressValue } = useMemo(() => { const { statusMessage, isUploading, progressValue } = useMemo(() => {
const status = data?.status; const status = data?.status;
const message = let message = '';
status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING if (status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING) {
? LL.WAIT_FIRMWARE() message = LL.WAIT_FIRMWARE();
: status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART } else if (status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART) {
? LL.APPLICATION_RESTARTING() message = LL.APPLICATION_RESTARTING();
: status === SystemStatusCodes.SYSTEM_STATUS_NORMAL } else if (status === SystemStatusCodes.SYSTEM_STATUS_NORMAL) {
? LL.RESTARTING_PRE() message = LL.RESTARTING_PRE();
: status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD } else if (status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD) {
? 'Upload Failed' message = 'Upload Failed';
: LL.RESTARTING_POST(); } else {
message = LL.RESTARTING_POST();
}
const uploading = const uploading =
status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING; status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING;
@@ -118,15 +120,17 @@ const SystemMonitor = () => {
p: 3 p: 3
}} }}
> >
<Box sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column' }}> <Box display="flex" alignItems="center" flexDirection="column">
<img <img
src="/app/icon.png" src="/app/icon.png"
alt="EMS-ESP" alt="EMS-ESP"
style={{ width: '40px', height: '40px', marginBottom: '16px' }} style={{ width: '40px', height: '40px', marginBottom: '16px' }}
/> />
<Typography <Typography
sx={{ color: 'secondary', fontWeight: 400, textAlign: 'center' }} color="secondary"
variant="h6" variant="h6"
fontWeight={400}
textAlign="center"
> >
{statusMessage} {statusMessage}
</Typography> </Typography>
@@ -146,14 +150,11 @@ const SystemMonitor = () => {
</MessageBox> </MessageBox>
) : ( ) : (
<> <>
<Typography <Typography mt={2} variant="h6" fontWeight={400} textAlign="center">
sx={{ mt: 2, fontWeight: 400, textAlign: 'center' }}
variant="h6"
>
{LL.PLEASE_WAIT()}&hellip; {LL.PLEASE_WAIT()}&hellip;
</Typography> </Typography>
{isUploading && ( {isUploading && (
<Box sx={{ width: '100%', pl: 2, pr: 2, py: 2 }}> <Box width="100%" pl={2} pr={2} py={2}>
<LinearProgressWithLabel value={progressValue} /> <LinearProgressWithLabel value={progressValue} />
</Box> </Box>
)} )}

View File

@@ -7,7 +7,6 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import { Link } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
@@ -25,6 +24,7 @@ import {
DialogTitle, DialogTitle,
Grid, Grid,
IconButton, IconButton,
Link,
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
@@ -274,7 +274,6 @@ const InstallDialog = memo(
fetchDevVersion, fetchDevVersion,
latestVersion, latestVersion,
latestDevVersion, latestDevVersion,
upgradeImportantMessageType,
downloadOnly, downloadOnly,
platform, platform,
LL, LL,
@@ -285,7 +284,6 @@ const InstallDialog = memo(
fetchDevVersion: boolean; fetchDevVersion: boolean;
latestVersion?: VersionInfo; latestVersion?: VersionInfo;
latestDevVersion?: VersionInfo; latestDevVersion?: VersionInfo;
upgradeImportantMessageType: number;
downloadOnly: boolean; downloadOnly: boolean;
platform: string; platform: string;
LL: TranslationFunctions; LL: TranslationFunctions;
@@ -309,24 +307,12 @@ const InstallDialog = memo(
{`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`} {`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`}
</DialogTitle> </DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography sx={{ mb: 2 }}> <Typography mb={2}>
{LL.INSTALL_VERSION( {LL.INSTALL_VERSION(
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(), downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
)} )}
</Typography> </Typography>
{upgradeImportantMessageType === 1 && LL.UPGRADE_IMPORTANT_MESSAGES_1()}
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
<Typography sx={{ mt: 2 }}>
<Link
target="_blank"
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
style={{ color: 'lightblue' }}
>
{LL.ONLINE_HELP()}
</Link>
</Typography>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
@@ -343,12 +329,7 @@ const InstallDialog = memo(
onClick={onClose} onClick={onClose}
color="primary" color="primary"
> >
<Link <Link underline="none" target="_blank" href={binURL} color="primary">
to={binURL}
target="_blank"
rel="noreferrer"
style={{ color: 'lightblue', textDecoration: 'none' }}
>
{LL.DOWNLOAD(0)} {LL.DOWNLOAD(0)}
</Link> </Link>
</Button> </Button>
@@ -390,9 +371,7 @@ const InstallPartitionDialog = memo(
{LL.INSTALL()} {LL.STORED_VERSIONS()} {LL.INSTALL()} {LL.STORED_VERSIONS()}
</DialogTitle> </DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography sx={{ mb: 2 }}> <Typography mb={2}>{LL.INSTALL_VERSION(LL.INSTALL(), version)}</Typography>
{LL.INSTALL_VERSION(LL.INSTALL(), version)}
</Typography>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
@@ -488,26 +467,6 @@ const Version = () => {
immediate: false immediate: false
}); });
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
useState<number>(0);
const { send: checkUpgradeImportantMessages } = useRequest(
(version: string) =>
callAction({ action: 'upgradeImportantMessages', param: version }),
{
immediate: false
}
)
.onSuccess((event) => {
const upgradeImportantMessageType_n = (
event.data as { upgradeImportantMessageType: number }
).upgradeImportantMessageType;
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
})
.onError((error) => {
toast.error(String(error.error?.message || 'An error occurred'));
});
// Memoized values // Memoized values
const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]); const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]);
@@ -573,16 +532,10 @@ const Version = () => {
[] []
); );
const showFirmwareDialog = useCallback( const showFirmwareDialog = useCallback((useDevVersion: boolean) => {
(useDevVersion: boolean) => { setFetchDevVersion(useDevVersion);
setFetchDevVersion(useDevVersion); setOpenInstallDialog(true);
void checkUpgradeImportantMessages( }, []);
useDevVersion ? latestDevVersion?.name : latestVersion?.name
);
setOpenInstallDialog(true);
},
[latestDevVersion, latestVersion, fetchDevVersion]
);
const closeInstallDialog = useCallback(() => { const closeInstallDialog = useCallback(() => {
setOpenInstallDialog(false); setOpenInstallDialog(false);
@@ -684,8 +637,8 @@ const Version = () => {
return ( return (
<> <>
<Box sx={{ p: 2, border: '1px solid #565656', borderRadius: 2 }}> <Box p={2} border="1px solid grey" borderRadius={2}>
<Typography sx={{ mb: 1 }} variant="h6" color="primary"> <Typography mb={1} variant="h6" color="primary">
{LL.THIS_VERSION()} {LL.THIS_VERSION()}
</Typography> </Typography>
@@ -750,7 +703,7 @@ const Version = () => {
{internetLive ? ( {internetLive ? (
<> <>
<Typography sx={{ mt: 4, mb: 1 }} variant="h6" color="primary"> <Typography mt={4} mb={1} variant="h6" color="primary">
{LL.AVAILABLE_VERSION()} {LL.AVAILABLE_VERSION()}
</Typography> </Typography>
@@ -772,7 +725,7 @@ const Version = () => {
</Grid> </Grid>
<Grid size={{ xs: 8, md: 10 }}> <Grid size={{ xs: 8, md: 10 }}>
{otherPartitions.map((partition) => ( {otherPartitions.map((partition) => (
<Typography key={partition.partition} sx={{ mb: 1 }}> <Typography key={partition.partition} mb={1}>
{partition.version} {partition.version}
<IconButton <IconButton
onClick={() => onClick={() =>
@@ -838,7 +791,7 @@ const Version = () => {
</Grid> </Grid>
</> </>
) : ( ) : (
<Typography sx={{ mt: 2 }} color="warning"> <Typography mt={2} color="warning">
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} /> <WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
{LL.INTERNET_CONNECTION_REQUIRED()} {LL.INTERNET_CONNECTION_REQUIRED()}
</Typography> </Typography>
@@ -862,7 +815,6 @@ const Version = () => {
fetchDevVersion={fetchDevVersion} fetchDevVersion={fetchDevVersion}
latestVersion={latestVersion} latestVersion={latestVersion}
latestDevVersion={latestDevVersion} latestDevVersion={latestDevVersion}
upgradeImportantMessageType={upgradeImportantMessageType}
downloadOnly={downloadOnly} downloadOnly={downloadOnly}
platform={platform} platform={platform}
LL={LL} LL={LL}
@@ -880,7 +832,7 @@ const Version = () => {
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
{LL.UPLOAD()} {LL.UPLOAD()}
</Typography> </Typography>
<SingleUpload doRestart={doRestart} /> <SingleUpload text={LL.UPLOAD_DROP_TEXT()} doRestart={doRestart} />
</> </>
)} )}
</Box> </Box>

View File

@@ -53,16 +53,12 @@ const MessageBox: FC<PropsWithChildren<MessageBoxProps>> = ({
return ( return (
<Box <Box
p={2}
display="flex"
alignItems="center"
borderRadius={1}
sx={{ backgroundColor, color: 'white', ...sx }}
{...rest} {...rest}
sx={{
display: 'flex',
alignItems: 'center',
borderRadius: 1,
backgroundColor,
color: 'white',
p: 2,
...sx
}}
> >
<Icon /> <Icon />
{(message || children) && ( {(message || children) && (

View File

@@ -29,7 +29,7 @@ const LayoutDrawerComponent = ({ mobileOpen, onClose }: LayoutDrawerProps) => {
() => ( () => (
<> <>
<Toolbar disableGutters> <Toolbar disableGutters>
<Box sx={{ display: 'flex', alignItems: 'center', p: 2 }}> <Box display="flex" alignItems="center" px={2}>
<LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} /> <LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} />
<Typography variant="h6">{PROJECT_NAME}</Typography> <Typography variant="h6">{PROJECT_NAME}</Typography>
</Box> </Box>

View File

@@ -51,7 +51,9 @@ const LayoutMenuComponent = () => {
sx={{ my: 0 }} sx={{ my: 0 }}
slotProps={{ slotProps={{
primary: { primary: {
sx: { fontWeight: 600, mb: '2px', color: 'lightblue' } fontWeight: '600',
mb: '2px',
color: 'lightblue'
} }
}} }}
/> />

View File

@@ -32,16 +32,8 @@ const FormLoaderComponent = ({ errorMessage, onRetry }: FormLoaderProps) => {
); );
} }
return ( return (
<Box <Box m={2} py={2} display="flex" alignItems="center" flexDirection="column">
sx={{ <Box py={2}>
m: 2,
py: 2,
display: 'flex',
alignItems: 'center',
flexDirection: 'column'
}}
>
<Box sx={{ p: 2 }}>
<CircularProgress size={100} /> <CircularProgress size={100} />
</Box> </Box>
</Box> </Box>

View File

@@ -15,14 +15,12 @@ const circularProgressStyles: SxProps<Theme> = (theme: Theme) => ({
const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => { const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => {
return ( return (
<Box <Box
sx={{ display="flex"
display: 'flex', alignItems="center"
alignItems: 'center', justifyContent="center"
justifyContent: 'center', flexDirection="column"
flexDirection: 'column', padding={2}
padding: 2, height={height}
height
}}
> >
<CircularProgress sx={circularProgressStyles} size={100} /> <CircularProgress sx={circularProgressStyles} size={100} />
</Box> </Box>

View File

@@ -1,4 +1,4 @@
// drag/drop code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0 // Code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
import { import {
type ChangeEvent, type ChangeEvent,
type DragEvent, type DragEvent,
@@ -6,28 +6,12 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import { Link } from 'react-router';
import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import CloudUploadIcon from '@mui/icons-material/CloudUpload'; import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import UploadIcon from '@mui/icons-material/Upload'; import UploadIcon from '@mui/icons-material/Upload';
import WarningIcon from '@mui/icons-material/Warning'; import { Box, Button, Typography, styled } from '@mui/material';
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Typography,
styled
} from '@mui/material';
import { callAction } from 'api/app';
import { dialogStyle } from '@/CustomTheme';
import { useRequest } from 'alova/client';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({ const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
@@ -74,29 +58,6 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
const [dragged, setDragged] = useState(false); const [dragged, setDragged] = useState(false);
const inputRef = useRef<HTMLInputElement | null>(null); const inputRef = useRef<HTMLInputElement | null>(null);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false);
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
useState<number>(0);
const { send: checkUpgradeImportantMessages } = useRequest(
(version: string) =>
callAction({ action: 'upgradeImportantMessages', param: version }),
{
immediate: false
}
)
.onSuccess((event) => {
const upgradeImportantMessageType_n = (
event.data as { upgradeImportantMessageType: number }
).upgradeImportantMessageType;
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
if (upgradeImportantMessageType_n === 0) {
onFileSelected(file);
}
})
.onError((error) => {
toast.error(String(error.error?.message || 'An error occurred'));
});
const checkFileExtension = (file: File) => { const checkFileExtension = (file: File) => {
const validExtensions = ['.json', '.bin', '.md5']; const validExtensions = ['.json', '.bin', '.md5'];
@@ -136,8 +97,9 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => { const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); event.stopPropagation();
void checkUpgradeImportantMessages(file?.name || ''); if (file) {
setShowUpgradeDialog(true); onFileSelected(file);
}
}; };
const handleBrowseClick = () => { const handleBrowseClick = () => {
@@ -196,55 +158,6 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
{LL.UPLOAD()} {LL.UPLOAD()}
</Button> </Button>
</Box> </Box>
{showUpgradeDialog && upgradeImportantMessageType > 0 && (
<Dialog
sx={dialogStyle}
open={showUpgradeDialog}
onClose={() => setShowUpgradeDialog(false)}
>
<DialogTitle>
<WarningIcon
color="warning"
sx={{ fontSize: 18, verticalAlign: 'middle' }}
/>
&nbsp;&nbsp;
{LL.UPGRADE_IMPORTANT_MESSAGES()}
</DialogTitle>
<DialogContent dividers>
{upgradeImportantMessageType === 1 &&
LL.UPGRADE_IMPORTANT_MESSAGES_1()}
{upgradeImportantMessageType === 2 &&
LL.UPGRADE_IMPORTANT_MESSAGES_2()}
<Typography sx={{ mt: 2 }}>
<Link
target="_blank"
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
style={{ color: 'lightblue' }}
>
{LL.ONLINE_HELP()}
</Link>
</Typography>
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => setShowUpgradeDialog(false)}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<UploadIcon />}
variant="outlined"
onClick={() => onFileSelected(file)}
color="primary"
>
{LL.UPLOAD()}
</Button>
</DialogActions>
</Dialog>
)}
</> </>
)} )}
</DocumentUploader> </DocumentUploader>

View File

@@ -13,10 +13,11 @@ import DragNdrop from './DragNdrop';
import { LinearProgressWithLabel } from './LinearProgressWithLabel'; import { LinearProgressWithLabel } from './LinearProgressWithLabel';
interface SingleUploadProps { interface SingleUploadProps {
text: string;
doRestart: () => void; doRestart: () => void;
} }
const SingleUpload = ({ doRestart }: SingleUploadProps) => { const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
const [md5, setMd5] = useState<string>(); const [md5, setMd5] = useState<string>();
const [file, setFile] = useState<File>(); const [file, setFile] = useState<File>();
const { LL } = useI18nContext(); const { LL } = useI18nContext();
@@ -57,7 +58,7 @@ const SingleUpload = ({ doRestart }: SingleUploadProps) => {
<> <>
{isUploading ? ( {isUploading ? (
<> <>
<Box sx={{ width: '100%', pl: 2, pr: 2 }}> <Box width="100%" pl={2} pr={2}>
<LinearProgressWithLabel <LinearProgressWithLabel
value={ value={
progress.total === 0 || progress.loaded === 0 progress.total === 0 || progress.loaded === 0
@@ -80,11 +81,11 @@ const SingleUpload = ({ doRestart }: SingleUploadProps) => {
</Button> </Button>
</> </>
) : ( ) : (
<DragNdrop text={LL.UPLOAD_DROP_TEXT()} onFileSelected={setFile} /> <DragNdrop text={text} onFileSelected={setFile} />
)} )}
{md5 && ( {md5 && (
<Box sx={{ mt: 2 }}> <Box mt={2}>
<Typography variant="body2">{'MD5: ' + md5}</Typography> <Typography variant="body2">{'MD5: ' + md5}</Typography>
</Box> </Box>
)} )}

View File

@@ -186,8 +186,7 @@ const cz: Translation = {
BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti', BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti',
COMPACT: 'Kompaktní', COMPACT: 'Kompaktní',
DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace', DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace',
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty', DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechna data',
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)', UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr', UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr',
ERROR: 'Neočekávaná chyba, zkuste to prosím znovu', ERROR: 'Neočekávaná chyba, zkuste to prosím znovu',
@@ -350,22 +349,15 @@ const cz: Translation = {
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul', NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
NO_DATA_2: 'pro jejich výběr.', NO_DATA_2: 'pro jejich výběr.',
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku', NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
NO_GPIO:'Nebylo nalezeno žádné volné GPIO',
THIS_VERSION: 'Tato verze', THIS_VERSION: 'Tato verze',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ sestavení', RELEASE_TYPE: 'Typ sestavení',
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení', INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi', SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
NO_DATA: 'Žádné údaje', NO_DATA: 'Žádná data',
USER_PROFILE: 'Uživatelský profil', USER_PROFILE: 'Uživatelský profil',
STORED_VERSIONS: 'Uložené verze', STORED_VERSIONS: 'Uložené verze'
ONLINE_HELP: 'online nápověda',
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovat důležité zprávy',
UPGRADE_IMPORTANT_MESSAGES_1: 'Tato aktualizace vyžaduje obnovení továrního nastavení. Ujistěte se, že jste vytvořili zálohu své konfigurace a nastavení před pokračováním a nahrajte ji po instalaci nové verze.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete se na novou hlavní verzi. Ujistěte se, že jste přečetli ChangeLog pro jakékoliv závažné změny.',
WARNING_SYSTEM_BACKUP: 'Toto vytvoří zálohu vašich celých systémových konfigurací a nastavení. Všechna hesla budou v zálohovém souboru čitelná. Buďte opatrní při sdílení! Opravdu chcete pokračovat?'
}; };
export default cz; export default cz;

View File

@@ -186,8 +186,7 @@ const de: Translation = {
BUFFER_SIZE: 'Max. Puffergröße', BUFFER_SIZE: 'Max. Puffergröße',
COMPACT: 'Kompakte Darstellung', COMPACT: 'Kompakte Darstellung',
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen', DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte', DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Daten',
DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung',
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch', UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier', UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.', ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
@@ -350,7 +349,6 @@ const de: Translation = {
NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul', NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul',
NO_DATA_2: ', um sie zu markieren.', NO_DATA_2: ', um sie zu markieren.',
NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu', NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu',
NO_GPIO:'Keine freien GPIO gefunden',
THIS_VERSION: 'Diese Version', THIS_VERSION: 'Diese Version',
PLATFORM: 'Plattform', PLATFORM: 'Plattform',
RELEASE_TYPE: 'Release Typ', RELEASE_TYPE: 'Release Typ',
@@ -359,13 +357,7 @@ const de: Translation = {
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation', FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
NO_DATA: 'Keine Daten', NO_DATA: 'Keine Daten',
USER_PROFILE: 'Benutzerprofil', USER_PROFILE: 'Benutzerprofil',
STORED_VERSIONS: 'Gespeicherte Versionen', STORED_VERSIONS: 'Gespeicherte Versionen'
ONLINE_HELP: 'Online-Hilfe',
UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten aktualisieren',
UPGRADE_IMPORTANT_MESSAGES_1: 'Diese Aktualisierung erfordert eine Werkseinstellung. Stellen Sie sicher, dass Sie eine Sicherung Ihrer Konfiguration und Einstellungen vor dem Fortfahren erstellt haben und diese nach der Installation der neuen Version hochladen.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Sie aktualisieren auf eine neue Hauptversion. Stellen Sie sicher, dass Sie den ChangeLog für alle wichtigen Änderungen gelesen haben.',
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und -einstellungen erstellen. Alle Passwörter werden im Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?'
}; };
export default de; export default de;

View File

@@ -186,8 +186,7 @@ const en: Translation = {
BUFFER_SIZE: 'Max Buffer Size', BUFFER_SIZE: 'Max Buffer Size',
COMPACT: 'Compact', COMPACT: 'Compact',
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
DOWNLOAD_SETTINGS_TEXT2: 'Export all values', DOWNLOAD_SETTINGS_TEXT2: 'Export all data',
DOWNLOAD_SYSTEM_BACKUP: 'System Backup',
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
ERROR: 'Unexpected Error, please try again', ERROR: 'Unexpected Error, please try again',
@@ -350,7 +349,6 @@ const en: Translation = {
NO_DATA_1: 'No favorite EMS entities found yet. Use the', NO_DATA_1: 'No favorite EMS entities found yet. Use the',
NO_DATA_2: 'module to mark them.', NO_DATA_2: 'module to mark them.',
NO_DATA_3: 'To see all available entities go to', NO_DATA_3: 'To see all available entities go to',
NO_GPIO:'No available GPIO found',
THIS_VERSION: 'This Version', THIS_VERSION: 'This Version',
PLATFORM: 'Platform', PLATFORM: 'Platform',
RELEASE_TYPE: 'Release Type', RELEASE_TYPE: 'Release Type',
@@ -359,13 +357,7 @@ const en: Translation = {
FIRMWARE_VERSION_INFO: 'Firmware Version Information', FIRMWARE_VERSION_INFO: 'Firmware Version Information',
NO_DATA: 'No data', NO_DATA: 'No data',
USER_PROFILE: 'User Profile', USER_PROFILE: 'User Profile',
STORED_VERSIONS: 'Stored Versions', STORED_VERSIONS: 'Stored Versions'
ONLINE_HELP: 'online help',
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Important Messages',
UPGRADE_IMPORTANT_MESSAGES_1: 'This upgrade requires a factory reset. Make sure you have made a backup of your configuration and settings before continuing, and upload this after the new version is installed.',
UPGRADE_IMPORTANT_MESSAGES_2: 'You are upgrading to a new major version. Make sure you have read the ChangeLog for any breaking changes.',
WARNING_SYSTEM_BACKUP: 'This will create a backup of your full system configuration and settings. All passwords will be readable in the backup file. Be careful with sharing! Do you want to continue?'
}; };
export default en; export default en;

View File

@@ -186,8 +186,7 @@ const fr: Translation = {
BUFFER_SIZE: 'Max taille du buffer', BUFFER_SIZE: 'Max taille du buffer',
COMPACT: 'Compact', COMPACT: 'Compact',
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations', DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs', DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les données',
DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système',
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)', UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
ERROR: 'Erreur inattendue, veuillez réessayer', ERROR: 'Erreur inattendue, veuillez réessayer',
@@ -350,7 +349,6 @@ const fr: Translation = {
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le', NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
NO_DATA_2: 'module pour les marquer.', NO_DATA_2: 'module pour les marquer.',
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à', NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
NO_GPIO:"Aucun GPIO disponible n'a été détecté",
THIS_VERSION: 'Cette version', THIS_VERSION: 'Cette version',
PLATFORM: 'Plateforme', PLATFORM: 'Plateforme',
RELEASE_TYPE: 'Type de version', RELEASE_TYPE: 'Type de version',
@@ -359,13 +357,7 @@ const fr: Translation = {
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware', FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
NO_DATA: 'Aucune donnée', NO_DATA: 'Aucune donnée',
USER_PROFILE: 'Profil utilisateur', USER_PROFILE: 'Profil utilisateur',
STORED_VERSIONS: 'Versions stockées', STORED_VERSIONS: 'Versions stockées'
ONLINE_HELP: 'aide en ligne',
UPGRADE_IMPORTANT_MESSAGES: 'Mettre à jour les messages importants',
UPGRADE_IMPORTANT_MESSAGES_1: 'Cette mise à jour nécessite une réinitialisation de fabrique. Assurez-vous d\'avoir créé une sauvegarde de vos configurations et paramètres avant de continuer et de la charger après l\'installation de la nouvelle version.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Vous mettez à jour vers une nouvelle version majeure. Assurez-vous de lire le ChangeLog pour tout changement important.',
WARNING_SYSTEM_BACKUP: 'Cela créera une sauvegarde de votre configuration et paramètres complets. Tous les mots de passe seront lisibles dans le fichier de sauvegarde. Soyez prudent avec le partage ! Voulez-vous continuer ?'
}; };
export default fr; export default fr;

View File

@@ -186,8 +186,7 @@ const it: Translation = {
BUFFER_SIZE: 'Max Buffer Size', BUFFER_SIZE: 'Max Buffer Size',
COMPACT: 'Compatto', COMPACT: 'Compatto',
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori', DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i dati',
DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema',
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
ERROR: 'Errore Inaspettato, prego tenta ancora', ERROR: 'Errore Inaspettato, prego tenta ancora',
@@ -350,7 +349,6 @@ const it: Translation = {
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il', NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
NO_DATA_2: 'modulo per marcarle.', NO_DATA_2: 'modulo per marcarle.',
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a', NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
NO_GPIO:'Non è stato trovato alcun GPIO disponibile',
THIS_VERSION: 'Questa versione', THIS_VERSION: 'Questa versione',
PLATFORM: 'Piattaforma', PLATFORM: 'Piattaforma',
RELEASE_TYPE: 'Tipo di rilascio', RELEASE_TYPE: 'Tipo di rilascio',
@@ -359,13 +357,7 @@ const it: Translation = {
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware', FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
NO_DATA: 'Nessun dato', NO_DATA: 'Nessun dato',
USER_PROFILE: 'Profilo utente', USER_PROFILE: 'Profilo utente',
STORED_VERSIONS: 'Versioni memorizzate', STORED_VERSIONS: 'Versioni memorizzate'
ONLINE_HELP: 'aiuto online',
UPGRADE_IMPORTANT_MESSAGES: 'Aggiorna Messaggi Importanti',
UPGRADE_IMPORTANT_MESSAGES_1: 'Questa aggiornamento richiede un ripristino di fabbrica. Assicurati di aver creato un backup delle tue configurazioni e impostazioni prima di continuare e di caricarlo dopo l\'installazione della nuova versione.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Stai aggiornando a una nuova versione principale. Assicurati di aver letto il ChangeLog per qualsiasi cambiamento importante.',
WARNING_SYSTEM_BACKUP: 'Questo creerà un backup delle tue configurazioni e impostazioni complete. Tutte le password saranno leggibili nel file di backup. Sei sicuro di voler continuare?'
}; };
export default it; export default it;

View File

@@ -27,7 +27,7 @@ const nl: Translation = {
REFRESH: 'Ververs', REFRESH: 'Ververs',
EXPORT: 'Export', EXPORT: 'Export',
FAVORITES: "Favorieten", FAVORITES: "Favorieten",
DEVICE_DETAILS: 'Apparaat Gegevens', DEVICE_DETAILS: 'Device Gegevens',
ID_OF: '{0} ID', ID_OF: '{0} ID',
DEVICE: 'Apparaat', DEVICE: 'Apparaat',
PRODUCT: 'Product', PRODUCT: 'Product',
@@ -65,7 +65,7 @@ const nl: Translation = {
TEMP_SENSOR: 'Temperatuur sensor', TEMP_SENSOR: 'Temperatuur sensor',
TEMP_SENSORS: 'Temperatuur Sensoren', TEMP_SENSORS: 'Temperatuur Sensoren',
WRITE_CMD_SENT: 'Schrijf commando gestuurd', WRITE_CMD_SENT: 'Schrijf commando gestuurd',
EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden loop dan de instellingen na en in het bijzonder het apparaat type profiel.', EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden dan loop de instellingen na en in het bijzonder het apparaat type profiel na.',
EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...', EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...',
CONNECTED: 'Verbonden', CONNECTED: 'Verbonden',
TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus', TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus',
@@ -75,7 +75,7 @@ const nl: Translation = {
EMS_DEVICE: 'EMS Apparaat', EMS_DEVICE: 'EMS Apparaat',
SUCCESS: 'SUCCESS', SUCCESS: 'SUCCESS',
FAIL: 'MISLUKT', FAIL: 'MISLUKT',
QUALITY: 'KWALITEIT', QUALITY: 'QUALITEIT',
SCAN: 'Scan', SCAN: 'Scan',
STATUS_NAMES: [ STATUS_NAMES: [
'EMS Telegrammen ontvangen (Rx)', 'EMS Telegrammen ontvangen (Rx)',
@@ -120,7 +120,7 @@ const nl: Translation = {
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)', ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding', ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
TRIGGER_TIME: 'Trigger tijd', TRIGGER_TIME: 'Trigger tijd',
COLD_SHOT_DURATION: 'Lengte koud water puls', COLD_SHOT_DURATION: 'Tijd Shot koud water',
FORMATTING_OPTIONS: 'Formatteringsopties', FORMATTING_OPTIONS: 'Formatteringsopties',
BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat web', BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat web',
BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT', BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT',
@@ -143,7 +143,7 @@ const nl: Translation = {
CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub', CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub',
CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen', CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen',
CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties', CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties',
CUSTOMIZATIONS_HELP_2: 'Markeer als favoriet', CUSTOMIZATIONS_HELP_2: 'Markeer as favoriet',
CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit', CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit',
CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API', CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API',
CUSTOMIZATIONS_HELP_5: 'verbergen voor apparaten', CUSTOMIZATIONS_HELP_5: 'verbergen voor apparaten',
@@ -186,13 +186,12 @@ const nl: Translation = {
BUFFER_SIZE: 'Max buffer grootte', BUFFER_SIZE: 'Max buffer grootte',
COMPACT: 'Compact', COMPACT: 'Compact',
DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen', DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen',
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden', DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle data',
DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup',
UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)', UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)',
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier', UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
ERROR: 'Onverwachte fout, probeer opnieuw', ERROR: 'Onverwachte fout, probeer opnieuw',
TIME_SET: 'Tijd ingesteld', TIME_SET: 'Tijd ingesteld',
MANAGE_USERS: 'Gebruikersbeheer', MANAGE_USERS: 'Beheer Gebruikers',
IS_ADMIN: 'is Admin', IS_ADMIN: 'is Admin',
USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren', USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren',
ADD: 'Toevoegen', ADD: 'Toevoegen',
@@ -201,7 +200,7 @@ const nl: Translation = {
GENERATING_TOKEN: 'Token aan het genereren', GENERATING_TOKEN: 'Token aan het genereren',
USER: 'Gebruiker', USER: 'Gebruiker',
MODIFY: 'Aanpassen', MODIFY: 'Aanpassen',
SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te ondertekenen en ook om admin privileges te activeren in de console.', SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te signeren en ook om admin privileges te activeren in de console.',
NOT_ENABLED: 'Niet geactiveerd', NOT_ENABLED: 'Niet geactiveerd',
ERRORS_OF: '{0} Foutmeldingen', ERRORS_OF: '{0} Foutmeldingen',
DISCONNECT_REASON: 'Verbinding verbroken vanwege', DISCONNECT_REASON: 'Verbinding verbroken vanwege',
@@ -350,7 +349,6 @@ const nl: Translation = {
NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de', NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de',
NO_DATA_2: 'module om ze te markeren.', NO_DATA_2: 'module om ze te markeren.',
NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar', NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar',
NO_GPIO:'Er is geen beschikbare GPIO gevonden',
THIS_VERSION: 'Deze Versie', THIS_VERSION: 'Deze Versie',
PLATFORM: 'Platform', PLATFORM: 'Platform',
RELEASE_TYPE: 'Release Typ', RELEASE_TYPE: 'Release Typ',
@@ -359,13 +357,7 @@ const nl: Translation = {
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie', FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
NO_DATA: 'Geen data', NO_DATA: 'Geen data',
USER_PROFILE: 'Gebruikersprofiel', USER_PROFILE: 'Gebruikersprofiel',
STORED_VERSIONS: 'Opgeslagen versies', STORED_VERSIONS: 'Opgeslagen versies'
ONLINE_HELP: 'online help',
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Belangrijke Berichten',
UPGRADE_IMPORTANT_MESSAGES_1: 'Deze upgrade vereist een fabrieksinstelling. Zorg ervoor dat u een back-up van uw configuratie en instellingen hebt gemaakt voordat u doorgaat en upload deze na de installatie van de nieuwe versie.',
UPGRADE_IMPORTANT_MESSAGES_2: 'U updatet naar een nieuwe grote versie. Zorg ervoor dat u de ChangeLog hebt gelezen voor alle brekende wijzigingen.',
WARNING_SYSTEM_BACKUP: 'Dit zal een back-up van uw volledige systeemconfiguratie en instellingen maken. Alle wachtwoorden zijn leesbaar in het back-upbestand. Wees voorzichtig bij delen! Wilt u doorgaan?'
}; };
export default nl; export default nl;

View File

@@ -186,8 +186,7 @@ const no: Translation = {
BUFFER_SIZE: 'Max Buffer Størrelse', BUFFER_SIZE: 'Max Buffer Størrelse',
COMPACT: 'Komprimere', COMPACT: 'Komprimere',
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger', DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier', DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle data',
DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi',
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)', UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her', UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
ERROR: 'Ukjent feil, prøv igjen', ERROR: 'Ukjent feil, prøv igjen',
@@ -350,7 +349,6 @@ const no: Translation = {
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk', NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
NO_DATA_2: 'modul for å markere dem.', NO_DATA_2: 'modul for å markere dem.',
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til', NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
NO_GPIO:'Det ble ikke funnet noen tilgjengelige GPIO-porter',
THIS_VERSION: 'Denne versjonen', THIS_VERSION: 'Denne versjonen',
PLATFORM: 'Plattform', PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelses type', RELEASE_TYPE: 'Utgivelses type',
@@ -359,13 +357,7 @@ const no: Translation = {
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon', FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
NO_DATA: 'Ingen data', NO_DATA: 'Ingen data',
USER_PROFILE: 'Brukerprofil', USER_PROFILE: 'Brukerprofil',
STORED_VERSIONS: 'Lagret versjoner', STORED_VERSIONS: 'Lagret versjoner'
ONLINE_HELP: 'online hjelp',
UPGRADE_IMPORTANT_MESSAGES: 'Oppdater viktige meldinger',
UPGRADE_IMPORTANT_MESSAGES_1: 'Denne oppdateringen krever en fabriksinstilling. Sørg for at du har laget en sikkerhetskopi av din konfigurasjon og innstillinger før du fortsetter, og last denne opp etter at den nye versjonen er installert.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Du oppdaterer til en ny hovedversjon. Sørg for at du har lest ChangeLog for eventuelle bruddende endringer.',
WARNING_SYSTEM_BACKUP: 'Dette vil lage en sikkerhetskopi av din fullstendige systemkonfigurasjon og innstillinger. Alle passord vil være lesbare i sikkerhetskopien. Vær forsiktig med deling! Vil du fortsette?'
}; };
export default no; export default no;

View File

@@ -186,8 +186,7 @@ const pl: BaseTranslation = {
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)', BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
COMPACT: 'Kompaktowy', COMPACT: 'Kompaktowy',
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji', DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości', DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie dane',
DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu',
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)', UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj', UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
@@ -350,7 +349,6 @@ const pl: BaseTranslation = {
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj', NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
NO_DATA_2: 'moduł do ich oznaczenia.', NO_DATA_2: 'moduł do ich oznaczenia.',
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do', NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
NO_GPIO:'Nie znaleziono dostępnych pinów GPIO',
THIS_VERSION: 'Ta wersja', THIS_VERSION: 'Ta wersja',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ wydania', RELEASE_TYPE: 'Typ wydania',
@@ -359,13 +357,7 @@ const pl: BaseTranslation = {
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware', FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
NO_DATA: 'Brak danych', NO_DATA: 'Brak danych',
USER_PROFILE: 'Profil użytkownika', USER_PROFILE: 'Profil użytkownika',
STORED_VERSIONS: 'Zapisane wersje', STORED_VERSIONS: 'Zapisane wersje'
ONLINE_HELP: 'pomoc online',
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizuj ważne wiadomości',
UPGRADE_IMPORTANT_MESSAGES_1: 'Ta aktualizacja wymaga resetu fabrycznego. Upewnij się, że masz utworzoną kopię swoich ustawień i konfiguracji przed kontynuowaniem i przesuń ją po zainstalowaniu nowej wersji.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujesz się do nowej głównej wersji. Upewnij się, że przeczytałeś ChangeLog dla wszelkich istotnych zmian.',
WARNING_SYSTEM_BACKUP: 'To spowoduje utworzenie kopii zapasowej całej konfiguracji i ustawień systemu. Wszystkie hasła będą widoczne w pliku kopii zapasowej. Bądź ostrożny przy udostępnianiu! Chcesz kontynuować?'
}; };
export default pl; export default pl;

View File

@@ -4,7 +4,7 @@ const sk: Translation = {
LANGUAGE: 'Jazyk', LANGUAGE: 'Jazyk',
RETRY: 'Opakovať', RETRY: 'Opakovať',
LOADING: 'Načítanie', LOADING: 'Načítanie',
IS_REQUIRED: '{0} je požadovaná', IS_REQUIRED: '{0} je požadovaných',
SIGN_IN: 'Prihlásiť sa', SIGN_IN: 'Prihlásiť sa',
SIGN_OUT: 'Odhlásiť sa', SIGN_OUT: 'Odhlásiť sa',
USERNAME: 'Užívateľské meno', USERNAME: 'Užívateľské meno',
@@ -186,8 +186,7 @@ const sk: Translation = {
BUFFER_SIZE: 'Buffer-max. veľkosť', BUFFER_SIZE: 'Buffer-max. veľkosť',
COMPACT: 'Kompaktné', COMPACT: 'Kompaktné',
DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení', DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení',
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty', DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky dáta',
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)', UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem', UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem',
ERROR: 'Neočakávaná chyba, prosím skúste to znova', ERROR: 'Neočakávaná chyba, prosím skúste to znova',
@@ -276,11 +275,11 @@ const sk: Translation = {
NETWORK_SUBNET: 'Maska podsiete', NETWORK_SUBNET: 'Maska podsiete',
NETWORK_DNS: 'DNS servery', NETWORK_DNS: 'DNS servery',
ADDRESS_OF: '{0} adresa', ADDRESS_OF: '{0} adresa',
ADMINISTRATOR: 'Administrátor', ADMINISTRATOR: 'Administrator',
GUEST: 'Hosť', GUEST: 'Hosť',
NEW: 'Novú', NEW: 'Nová',
NEW_NAME_OF: 'Nový názov {0}', NEW_NAME_OF: 'Nový názov {0}',
ENTITY: 'entitu', ENTITY: 'entita',
MIN: 'min', MIN: 'min',
MAX: 'max', MAX: 'max',
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny', BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
@@ -350,7 +349,6 @@ const sk: Translation = {
NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite', NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite',
NO_DATA_2: 'modul na ich označenie.', NO_DATA_2: 'modul na ich označenie.',
NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na', NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na',
NO_GPIO:'Nebol nájdený žiadny dostupný GPIO',
THIS_VERSION: 'Táto verzia', THIS_VERSION: 'Táto verzia',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ vydania', RELEASE_TYPE: 'Typ vydania',
@@ -359,13 +357,7 @@ const sk: Translation = {
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware', FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
NO_DATA: 'Žiadne dáta', NO_DATA: 'Žiadne dáta',
USER_PROFILE: 'Profil používateľa', USER_PROFILE: 'Profil používateľa',
STORED_VERSIONS: 'Uložené verzie', STORED_VERSIONS: 'Uložené verzie'
ONLINE_HELP: 'online pomoc',
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovať dôležité správy',
UPGRADE_IMPORTANT_MESSAGES_1: 'Táto aktualizácia vyžaduje reštart základných nastavení. Uistite sa, že ste vytvorili zálohu svojich konfigurácií a nastavení pred pokračovaním a nahrajte ju po instalácii novej verzie.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete sa na novú hlavnú verziu. Uistite sa, že ste prečítali ChangeLog pre akékoľvek dôležité zmeny.',
WARNING_SYSTEM_BACKUP: 'Toto vytvorí zálohu všetkých vašich celých systémových konfigurácií a nastavení. Všetky hesla budú čitateľné v zálohovom súbore. Buďte opatrní pri zdieľaní! Chcete pokračovať?'
}; };
export default sk; export default sk;

View File

@@ -186,8 +186,7 @@ const sv: Translation = {
BUFFER_SIZE: 'Max bufferstorlek', BUFFER_SIZE: 'Max bufferstorlek',
COMPACT: 'Komprimerad', COMPACT: 'Komprimerad',
DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar', DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar',
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden', DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla data',
DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia',
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)', UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här', UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här',
ERROR: 'Okänt fel, var god försök igen', ERROR: 'Okänt fel, var god försök igen',
@@ -350,7 +349,6 @@ const sv: Translation = {
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd', NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
NO_DATA_2: 'modul för att markera dem.', NO_DATA_2: 'modul för att markera dem.',
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till', NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
NO_GPIO:'Inga tillgängliga GPIO-portar hittades',
THIS_VERSION: 'Denna version', THIS_VERSION: 'Denna version',
PLATFORM: 'Plattform', PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelsestyp', RELEASE_TYPE: 'Utgivelsestyp',
@@ -359,13 +357,7 @@ const sv: Translation = {
FIRMWARE_VERSION_INFO: 'Information om firmwareversion', FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
NO_DATA: 'Ingen data', NO_DATA: 'Ingen data',
USER_PROFILE: 'Användarprofil', USER_PROFILE: 'Användarprofil',
STORED_VERSIONS: 'Lagrad versioner', STORED_VERSIONS: 'Lagrad versioner'
ONLINE_HELP: 'online hjälp',
UPGRADE_IMPORTANT_MESSAGES: 'Uppdatera viktiga meddelanden',
UPGRADE_IMPORTANT_MESSAGES_1: 'Denna uppdatering kräver en fabriksåterställning. Se till att du har gjort en säkerhetskopia av din konfiguration och inställningar innan du fortsätter och ladda upp denna efter att den nya versionen är installerad.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Du uppdaterar till en ny huvudversion. Se till att du har läst ChangeLog för eventuella brkande ändringar.',
WARNING_SYSTEM_BACKUP: 'Detta kommer att skapa en säkerhetskopia av din fullständiga systemkonfiguration och inställningar. Alla lösenord kommer att vara läsbara i säkerhetskopien. Var försiktig med att dela! Vill du fortsätta?'
}; };
export default sv; export default sv;

View File

@@ -186,8 +186,7 @@ const tr: Translation = {
BUFFER_SIZE: 'En fazla bellek boyutu', BUFFER_SIZE: 'En fazla bellek boyutu',
COMPACT: 'Sıkışık', COMPACT: 'Sıkışık',
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın', DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al', DOWNLOAD_SETTINGS_TEXT2: 'Tüm verileri dışarı al',
DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme',
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle', UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın', UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
@@ -350,7 +349,6 @@ const tr: Translation = {
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın', NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
NO_DATA_2: 'modülünü kullanın.', NO_DATA_2: 'modülünü kullanın.',
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git', NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
NO_GPIO:'Kullanılabilir GPIO bulunamadı',
THIS_VERSION: 'Bu Sürüm', THIS_VERSION: 'Bu Sürüm',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Sürüm Tipi', RELEASE_TYPE: 'Sürüm Tipi',
@@ -359,13 +357,7 @@ const tr: Translation = {
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi', FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
NO_DATA: 'Hiçbir veri yok', NO_DATA: 'Hiçbir veri yok',
USER_PROFILE: 'Kullanıcı Profili', USER_PROFILE: 'Kullanıcı Profili',
STORED_VERSIONS: 'Kaydedilmiş Sürümler', STORED_VERSIONS: 'Kaydedilmiş Sürümler'
ONLINE_HELP: 'online yardım',
UPGRADE_IMPORTANT_MESSAGES: 'Önemli Mesajları Güncelle',
UPGRADE_IMPORTANT_MESSAGES_1: 'Bu güncelleme továrnı ayarlarını gerektirir. Yapılandırmanızı ve ayarlarınızı önce yedekleyin ve ardından yeni sürüm yüklendikten sonra yükleyin.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Yeni bir büyük sürüme yükselteceksiniz. Değişiklikleri ChangeLogı okuduğunuzdan emin olun.',
WARNING_SYSTEM_BACKUP: 'Bu, sistem yapılandırmanızı ve ayarlarınızın bir yedeklemesi oluşturacaktır. Tüm şifreler yedekleme dosyasında okunabilir olacaktır. Paylaşırken dikkatli olun! Devam etmek istediğinize emin misiniz?'
}; };
export default tr; export default tr;

View File

@@ -23,8 +23,6 @@ export const saveFile = (
}, 100); }, 100);
} catch (error) { } catch (error) {
console.error('Failed to save file:', error); console.error('Failed to save file:', error);
throw new Error(`Unable to save file: ${filename}${extension}`, { throw new Error(`Unable to save file: ${filename}${extension}`);
cause: error
});
} }
}; };

View File

@@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
const DEFAULT_DELAY = 5000; const DEFAULT_DELAY = 3000;
/** /**
* Custom hook for setting up an interval with proper cleanup * Custom hook for setting up an interval with proper cleanup

View File

@@ -2,8 +2,9 @@ import preact from '@preact/preset-vite';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { visualizer } from 'rollup-plugin-visualizer'; import { visualizer } from 'rollup-plugin-visualizer';
import { Plugin, PluginOption, defineConfig } from 'vite'; import { Plugin, defineConfig } from 'vite';
import viteImagemin from 'vite-plugin-imagemin'; import viteImagemin from 'vite-plugin-imagemin';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import zlib from 'zlib'; import zlib from 'zlib';
// @ts-expect-error - mock server doesn't have type declarations // @ts-expect-error - mock server doesn't have type declarations
@@ -98,31 +99,16 @@ const createPreactPlugin = (devToolsEnabled: boolean) =>
prefreshEnabled: false prefreshEnabled: false
}); });
// Patch preact/compat to export stub React 19 APIs (use, useOptimistic) so that
// react-router v7 doesn't trigger IMPORT_IS_UNDEFINED warnings from Rolldown.
const preactCompatPatchPlugin = (): Plugin => ({
name: 'preact-compat-react19-patch',
transform(code, id) {
if (id.includes('preact') && id.includes('compat.module.js')) {
return {
code:
code +
'\nexport var use = undefined;\nexport var useOptimistic = undefined;\n',
map: null
};
}
return undefined;
}
});
// Common base plugins // Common base plugins
const createBasePlugins = ( const createBasePlugins = (
devToolsEnabled: boolean, devToolsEnabled: boolean,
includeBundleReporter = true includeBundleReporter = true
): PluginOption[] => { ) => {
const plugins: PluginOption[] = [ const plugins = [
createPreactPlugin(devToolsEnabled), createPreactPlugin(devToolsEnabled),
preactCompatPatchPlugin() viteTsconfigPaths({
projects: ['./tsconfig.json']
})
]; ];
if (includeBundleReporter) { if (includeBundleReporter) {
plugins.push(bundleSizeReporter()); plugins.push(bundleSizeReporter());
@@ -248,8 +234,7 @@ export default defineConfig(
plugins: [...createBasePlugins(true, true), mockServer()], plugins: [...createBasePlugins(true, true), mockServer()],
resolve: { resolve: {
alias: RESOLVE_ALIASES, alias: RESOLVE_ALIASES,
extensions: RESOLVE_EXTENSIONS, extensions: RESOLVE_EXTENSIONS
tsconfigPaths: true
}, },
server: { server: {
open: true, open: true,
@@ -278,8 +263,7 @@ export default defineConfig(
plugins: createBasePlugins(false, true), plugins: createBasePlugins(false, true),
resolve: { resolve: {
alias: RESOLVE_ALIASES, alias: RESOLVE_ALIASES,
extensions: RESOLVE_EXTENSIONS, extensions: RESOLVE_EXTENSIONS
tsconfigPaths: true
}, },
build: { build: {
...createBaseBuildConfig(), ...createBaseBuildConfig(),
@@ -313,8 +297,7 @@ export default defineConfig(
], ],
resolve: { resolve: {
alias: RESOLVE_ALIASES, alias: RESOLVE_ALIASES,
extensions: RESOLVE_EXTENSIONS, extensions: RESOLVE_EXTENSIONS
tsconfigPaths: true
}, },
build: { build: {
...createBaseBuildConfig(), ...createBaseBuildConfig(),
@@ -323,7 +306,8 @@ export default defineConfig(
rollupOptions: { rollupOptions: {
treeshake: { treeshake: {
moduleSideEffects: false, moduleSideEffects: false,
propertyReadSideEffects: false as const, propertyReadSideEffects: false,
tryCatchDeoptimization: false,
unknownGlobalSideEffects: false unknownGlobalSideEffects: false
}, },
output: { output: {

View File

@@ -148,7 +148,9 @@
#elif defined(ARDUINO_ARCH_ESP32) #elif defined(ARDUINO_ARCH_ESP32)
#include <driver/rtc_io.h> #include <driver/rtc_io.h>
#include <soc/gpio_struct.h> #include <soc/gpio_struct.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include "soc/gpio_periph.h" #include "soc/gpio_periph.h"
#endif // ESP_IDF_VERSION_MAJOR >= 5
#define PIN_TO_BASEREG(pin) (0) #define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin) #define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t #define IO_REG_TYPE uint32_t

View File

@@ -12,9 +12,7 @@
// Include all library components // Include all library components
#include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector #include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector
#include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector #include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector
#if CONFIG_IDF_TARGET_ESP32 #include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector (ESP32 only)
#endif
// #include "esp32-psram/InMemoryFile.h" // File interface using vectors // #include "esp32-psram/InMemoryFile.h" // File interface using vectors
// #include "esp32-psram/PSRAM.h" // PSRAM file system // #include "esp32-psram/PSRAM.h" // PSRAM file system
// #include "esp32-psram/HIMEM.h" // HIMEM file system // #include "esp32-psram/HIMEM.h" // HIMEM file system

View File

@@ -1,8 +1,5 @@
#pragma once #pragma once
// HIMEM is only available on original ESP32
#if CONFIG_IDF_TARGET_ESP32
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <memory> #include <memory>
@@ -363,5 +360,3 @@ class HimemBlock {
}; };
} // namespace esp32_psram } // namespace esp32_psram
#endif // CONFIG_IDF_TARGET_ESP32

View File

@@ -238,9 +238,7 @@ using RingBufferStreamPSRAM = RingBufferStream<VectorPSRAM<uint8_t>>;
/** /**
* @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage * @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage
*/ */
#if CONFIG_IDF_TARGET_ESP32
using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>; using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>;
#endif
/** /**
* @brief Type alias for a RingBufferStream that uses std::vector storage * @brief Type alias for a RingBufferStream that uses std::vector storage

View File

@@ -209,10 +209,8 @@ using TypedRingBufferRAM = TypedRingBuffer<T, std::vector<T>>;
/** /**
* @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage * @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage
*/ */
#if CONFIG_IDF_TARGET_ESP32
template<typename T> template<typename T>
using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>; using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>;
#endif
/** /**
* @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage * @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage

View File

@@ -1,8 +1,5 @@
#pragma once #pragma once
// HIMEM is only available on original ESP32
#if CONFIG_IDF_TARGET_ESP32
#include "HimemBlock.h" #include "HimemBlock.h"
namespace esp32_psram { namespace esp32_psram {
@@ -529,6 +526,4 @@ void swap(VectorHIMEM<T>& lhs, VectorHIMEM<T>& rhs) noexcept {
lhs.swap(rhs); lhs.swap(rhs);
} }
} // namespace esp32_psram } // namespace esp32_psram
#endif // CONFIG_IDF_TARGET_ESP32

View File

@@ -49,10 +49,6 @@ the LICENSE file.
#define EMC_CLIENTID_LENGTH 23 + 1 #define EMC_CLIENTID_LENGTH 23 + 1
#endif #endif
#ifdef EMSESP_MQTT_STACKSIZE
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
#endif
#ifndef EMC_TASK_STACK_SIZE #ifndef EMC_TASK_STACK_SIZE
#define EMC_TASK_STACK_SIZE 5120 #define EMC_TASK_STACK_SIZE 5120
#endif #endif
@@ -70,10 +66,14 @@ the LICENSE file.
#endif #endif
#if EMC_USE_MEMPOOL #if EMC_USE_MEMPOOL
#ifndef EMC_NUM_POOL_ELEMENTS #ifndef EMC_NUM_POOL_ELEMENTS
#define EMC_NUM_POOL_ELEMENTS 32 #define EMC_NUM_POOL_ELEMENTS 32
#endif #endif
#ifndef EMC_SIZE_POOL_ELEMENTS #ifndef EMC_SIZE_POOL_ELEMENTS
#define EMC_SIZE_POOL_ELEMENTS 128 #define EMC_SIZE_POOL_ELEMENTS 128
#endif
#endif #endif
#ifndef TASMOTA_SDK
#define EMC_CLIENT_SECURE
#endif #endif

View File

@@ -62,11 +62,7 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
_xSemaphore = xSemaphoreCreateMutex(); _xSemaphore = xSemaphoreCreateMutex();
EMC_SEMAPHORE_GIVE(); // release before first use EMC_SEMAPHORE_GIVE(); // release before first use
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) { if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
if (core > 1) { xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
} else {
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
}
} }
#else #else
(void) useInternalTask; (void) useInternalTask;
@@ -74,7 +70,6 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
(void) core; (void) core;
#endif #endif
_clientId = _generatedClientId; _clientId = _generatedClientId;
_core = core;
} }
MqttClient::~MqttClient() { MqttClient::~MqttClient() {

View File

@@ -69,17 +69,7 @@ class MqttClient {
const char* getClientId() const; const char* getClientId() const;
size_t queueSize(); // No const because of mutex size_t queueSize(); // No const because of mutex
void loop(); void loop();
uint32_t stack() {
#ifndef EMSESP_STANDALONE
return uxTaskGetStackHighWaterMark(_taskHandle);
#else
return 0;
#endif
}
uint8_t core() {
return _core;
}
protected: protected:
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1); explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
espMqttClientTypes::UseInternalTask _useInternalTask; espMqttClientTypes::UseInternalTask _useInternalTask;
@@ -108,7 +98,6 @@ class MqttClient {
uint8_t _willQos; uint8_t _willQos;
bool _willRetain; bool _willRetain;
uint32_t _timeout; uint32_t _timeout;
uint8_t _core;
// state is protected to allow state changes by the transport system, defined in child classes // state is protected to allow state changes by the transport system, defined in child classes
// eg. to allow AsyncTCP // eg. to allow AsyncTCP

View File

@@ -8,7 +8,7 @@ the LICENSE file.
#include "ClientPosix.h" #include "ClientPosix.h"
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__)
namespace espMqttClientInternals { namespace espMqttClientInternals {

View File

@@ -8,7 +8,7 @@ the LICENSE file.
#pragma once #pragma once
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__)
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@@ -6,65 +6,66 @@ For a copy, see <https://opensource.org/licenses/MIT> or
the LICENSE file. the LICENSE file.
*/ */
#ifndef NO_TLS_SUPPORT #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#include "ClientSecureSync.h" #include "ClientSecureSync.h"
#include <lwip/sockets.h> #include <lwip/sockets.h> // socket options
#include "../Config.h"
namespace espMqttClientInternals { namespace espMqttClientInternals {
ClientSecureSync::ClientSecureSync() ClientSecureSync::ClientSecureSync()
: client() { : client() {
client.setClient(&basic_client, true); // empty
client.setBufferSizes(EMC_RX_BUFFER_SIZE, EMC_TX_BUFFER_SIZE);
client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
}
ClientSecureSync::~ClientSecureSync() {
stop();
} }
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) { bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
if (ret) { if (ret) {
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure #if defined(ARDUINO_ARCH_ESP8266)
int val = true; client.setNoDelay(true);
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int)); #elif defined(ARDUINO_ARCH_ESP32)
} // Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
return ret; int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
}
return ret;
} }
bool ClientSecureSync::connect(const char * host, uint16_t port) { bool ClientSecureSync::connect(const char* host, uint16_t port) {
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
if (ret) { if (ret) {
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure #if defined(ARDUINO_ARCH_ESP8266)
int val = true; client.setNoDelay(true);
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int)); #elif defined(ARDUINO_ARCH_ESP32)
} // Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
return ret; int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
}
return ret;
} }
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) { size_t ClientSecureSync::write(const uint8_t* buf, size_t size) {
return client.write(buf, size); return client.write(buf, size);
} }
int ClientSecureSync::read(uint8_t * buf, size_t size) { int ClientSecureSync::read(uint8_t* buf, size_t size) {
return client.read(buf, size); return client.read(buf, size);
} }
void ClientSecureSync::stop() { void ClientSecureSync::stop() {
client.stop(); client.stop();
} }
bool ClientSecureSync::connected() { bool ClientSecureSync::connected() {
return client.connected(); return client.connected();
} }
bool ClientSecureSync::disconnected() { bool ClientSecureSync::disconnected() {
return !client.connected(); return !client.connected();
} }
} // namespace espMqttClientInternals } // namespace espMqttClientInternals
#endif #endif

View File

@@ -8,11 +8,15 @@ the LICENSE file.
#pragma once #pragma once
#ifndef NO_TLS_SUPPORT #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
// #include "esp_tls.h" // Added for EMS-ESP
#include "../Config.h"
#if defined(EMC_CLIENT_SECURE)
#include <WiFiClientSecure.h> // includes IPAddress
#else
#include <WiFiClient.h> #include <WiFiClient.h>
#include <ESP_SSLClient.h> #endif
#include "Transport.h" #include "Transport.h"
namespace espMqttClientInternals { namespace espMqttClientInternals {
@@ -20,7 +24,6 @@ namespace espMqttClientInternals {
class ClientSecureSync : public Transport { class ClientSecureSync : public Transport {
public: public:
ClientSecureSync(); ClientSecureSync();
~ClientSecureSync();
bool connect(IPAddress ip, uint16_t port) override; bool connect(IPAddress ip, uint16_t port) override;
bool connect(const char * host, uint16_t port) override; bool connect(const char * host, uint16_t port) override;
size_t write(const uint8_t * buf, size_t size) override; size_t write(const uint8_t * buf, size_t size) override;
@@ -28,11 +31,14 @@ class ClientSecureSync : public Transport {
void stop() override; void stop() override;
bool connected() override; bool connected() override;
bool disconnected() override; bool disconnected() override;
// added for EMS-ESP
WiFiClient basic_client; #if defined(EMC_CLIENT_SECURE)
ESP_SSLClient client; WiFiClientSecure client;
#else
WiFiClient client;
#endif
}; };
} // namespace espMqttClientInternals } // namespace espMqttClientInternals
#endif #endif

View File

@@ -8,6 +8,50 @@ the LICENSE file.
#include "espMqttClient.h" #include "espMqttClient.h"
#if defined(ARDUINO_ARCH_ESP8266)
espMqttClient::espMqttClient()
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
, _client() {
_transport = &_client;
}
espMqttClientSecure::espMqttClientSecure()
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
, _client() {
_transport = &_client;
}
espMqttClientSecure & espMqttClientSecure::setInsecure() {
_client.client.setInsecure();
return *this;
}
espMqttClientSecure & espMqttClientSecure::setFingerprint(const uint8_t fingerprint[20]) {
_client.client.setFingerprint(fingerprint);
return *this;
}
espMqttClientSecure & espMqttClientSecure::setTrustAnchors(const X509List * ta) {
_client.client.setTrustAnchors(ta);
return *this;
}
espMqttClientSecure & espMqttClientSecure::setClientRSACert(const X509List * cert, const PrivateKey * sk) {
_client.client.setClientRSACert(cert, sk);
return *this;
}
espMqttClientSecure & espMqttClientSecure::setClientECCert(const X509List * cert, const PrivateKey * sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
_client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCertStore(CertStoreBase * certStore) {
_client.client.setCertStore(certStore);
return *this;
}
#endif
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask) espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask)
: MqttClientSetup(useInternalTask) : MqttClientSetup(useInternalTask)
@@ -34,45 +78,51 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
} }
espMqttClientSecure & espMqttClientSecure::setInsecure() { espMqttClientSecure & espMqttClientSecure::setInsecure() {
#ifndef NO_TLS_SUPPORT #if defined(EMC_CLIENT_SECURE)
_client.client.setInsecure(); _client.client.setInsecure();
#endif #endif
return *this; return *this;
} }
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) { espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
#ifndef NO_TLS_SUPPORT #if defined(EMC_CLIENT_SECURE)
_client.client.setCACert(rootCA); _client.client.setCACert(rootCA);
#endif #endif
return *this; return *this;
} }
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) { espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
#ifndef NO_TLS_SUPPORT #if defined(EMC_CLIENT_SECURE)
_client.client.setCertificate(clientCa); _client.client.setCertificate(clientCa);
#endif #endif
return *this; return *this;
} }
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) { espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
#ifndef NO_TLS_SUPPORT #if defined(EMC_CLIENT_SECURE)
_client.client.setPrivateKey(privateKey); _client.client.setPrivateKey(privateKey);
#endif #endif
return *this; return *this;
} }
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) { espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
#ifndef NO_TLS_SUPPORT #if defined(EMC_CLIENT_SECURE)
_client.client.setPreSharedKey(pskIdent, psKey);
#endif #endif
return *this; return *this;
} }
#endif #endif
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__)
espMqttClient::espMqttClient() espMqttClient::espMqttClient()
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO) : MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
, _client() { , _client() {
_transport = &_client; _transport = &_client;
} }
#elif defined(_WIN32) || defined(__APPLE__)
// Windows
espMqttClient::espMqttClient()
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO) {
}
#endif #endif

View File

@@ -14,7 +14,7 @@ the LICENSE file.
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#include "Transport/ClientSync.h" #include "Transport/ClientSync.h"
#include "Transport/ClientSecureSync.h" #include "Transport/ClientSecureSync.h"
#elif defined(__linux__) || defined(__APPLE__) #elif defined(__linux__)
#include "Transport/ClientPosix.h" #include "Transport/ClientPosix.h"
#endif #endif
@@ -65,16 +65,10 @@ class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey); espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey);
protected: protected:
#ifndef NO_TLS_SUPPORT
espMqttClientInternals::ClientSecureSync _client; espMqttClientInternals::ClientSecureSync _client;
#else
espMqttClientInternals::ClientSync _client;
#endif
}; };
#endif #elif defined(__linux__)
#if defined(__linux__) || defined(__APPLE__)
class espMqttClient : public MqttClientSetup<espMqttClient> { class espMqttClient : public MqttClientSetup<espMqttClient> {
public: public:
espMqttClient(); espMqttClient();
@@ -82,4 +76,10 @@ class espMqttClient : public MqttClientSetup<espMqttClient> {
protected: protected:
espMqttClientInternals::ClientPosix _client; espMqttClientInternals::ClientPosix _client;
}; };
#elif defined(_WIN32) || defined(__APPLE__)
class espMqttClient : public MqttClientSetup<espMqttClient> {
public:
espMqttClient();
};
#endif #endif

View File

@@ -34,7 +34,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <esp32-psram.h>
#include <uuid/common.h> #include <uuid/common.h>
#include <uuid/log.h> #include <uuid/log.h>
@@ -1646,22 +1645,22 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
uint8_t cursor_ = 0; /*!< cursor position from end of line */ uint8_t cursor_ = 0; /*!< cursor position from end of line */
uint8_t esc_ = 0; /*!< esc sequence running */ uint8_t esc_ = 0; /*!< esc sequence running */
Stream & stream_; /*!< Stream used for the input/output of this shell. @since 3.0.0 */ Stream & stream_; /*!< Stream used for the input/output of this shell. @since 3.0.0 */
std::shared_ptr<Commands> commands_; /*!< Commands available for execution in this shell. @since 0.1.0 */ std::shared_ptr<Commands> commands_; /*!< Commands available for execution in this shell. @since 0.1.0 */
std::deque<unsigned int, AllocatorPSRAM<unsigned int>> context_; /*!< Context stack for this shell. Affects which commands are available. Should never be empty. @since 0.1.0 */ std::deque<unsigned int> context_; /*!< Context stack for this shell. Affects which commands are available. Should never be empty. @since 0.1.0 */
unsigned int flags_ = 0; /*!< Current flags for this shell. Affects which commands are available. @since 0.1.0 */ unsigned int flags_ = 0; /*!< Current flags for this shell. Affects which commands are available. @since 0.1.0 */
#if UUID_CONSOLE_THREAD_SAFE #if UUID_CONSOLE_THREAD_SAFE
mutable std::mutex mutex_; /*!< Mutex for queued log messages. @since 1.0.0 */ mutable std::mutex mutex_; /*!< Mutex for queued log messages. @since 1.0.0 */
#endif #endif
unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 0.1.0 */ unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 0.1.0 */
std::list<QueuedLogMessage, AllocatorPSRAM<QueuedLogMessage>> log_messages_; /*!< Queued log messages, in the order they were received. @since 0.1.0 */ std::list<QueuedLogMessage> log_messages_; /*!< Queued log messages, in the order they were received. @since 0.1.0 */
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */ size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */
std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */ std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */
size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */ size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */
unsigned char previous_ = 0; /*!< Previous character that was entered on the command line. Used to detect CRLF line endings. @since 0.1.0 */ unsigned char previous_ = 0; /*!< Previous character that was entered on the command line. Used to detect CRLF line endings. @since 0.1.0 */
Mode mode_ = Mode::NORMAL; /*!< Current execution mode. @since 0.1.0 */ Mode mode_ = Mode::NORMAL; /*!< Current execution mode. @since 0.1.0 */
std::unique_ptr<ModeData> mode_data_ = nullptr; /*!< Data associated with the current execution mode. @since 0.1.0 */ std::unique_ptr<ModeData> mode_data_ = nullptr; /*!< Data associated with the current execution mode. @since 0.1.0 */
bool stopped_ = false; /*!< Indicates that the shell has been stopped. @since 0.1.0 */ bool stopped_ = false; /*!< Indicates that the shell has been stopped. @since 0.1.0 */
bool prompt_displayed_ = false; /*!< Indicates that a command prompt has been displayed, so that the output of invoke_command() is correct. @since 0.1.0 */ bool prompt_displayed_ = false; /*!< Indicates that a command prompt has been displayed, so that the output of invoke_command() is correct. @since 0.1.0 */
uint64_t idle_time_ = 0; /*!< Time the shell became idle. @since 0.7.0 */ uint64_t idle_time_ = 0; /*!< Time the shell became idle. @since 0.7.0 */
uint64_t idle_timeout_ = 0; /*!< Idle timeout (in milliseconds). @since 0.7.0 */ uint64_t idle_timeout_ = 0; /*!< Idle timeout (in milliseconds). @since 0.7.0 */
@@ -1787,7 +1786,7 @@ class CommandLine {
* @return A reference to the parameters. * @return A reference to the parameters.
* @since 0.6.0 * @since 0.6.0
*/ */
inline std::vector<std::string, AllocatorPSRAM<std::string>> & operator*() { inline std::vector<std::string> & operator*() {
return parameters_; return parameters_;
} }
/** /**
@@ -1796,7 +1795,7 @@ class CommandLine {
* @return A reference to the parameters. * @return A reference to the parameters.
* @since 0.6.0 * @since 0.6.0
*/ */
inline const std::vector<std::string, AllocatorPSRAM<std::string>> & operator*() const { inline const std::vector<std::string> & operator*() const {
return parameters_; return parameters_;
} }
/** /**
@@ -1805,7 +1804,7 @@ class CommandLine {
* @return A pointer to the parameters. * @return A pointer to the parameters.
* @since 0.4.0 * @since 0.4.0
*/ */
inline std::vector<std::string, AllocatorPSRAM<std::string>> * operator->() { inline std::vector<std::string> * operator->() {
return &parameters_; return &parameters_;
} }
/** /**
@@ -1814,7 +1813,7 @@ class CommandLine {
* @return A pointer to the parameters. * @return A pointer to the parameters.
* @since 0.4.0 * @since 0.4.0
*/ */
inline const std::vector<std::string, AllocatorPSRAM<std::string>> * operator->() const { inline const std::vector<std::string> * operator->() const {
return &parameters_; return &parameters_;
} }
@@ -1844,8 +1843,8 @@ class CommandLine {
bool trailing_space = false; /*!< Command line has a trailing space. @since 0.4.0 */ bool trailing_space = false; /*!< Command line has a trailing space. @since 0.4.0 */
private: private:
std::vector<std::string, AllocatorPSRAM<std::string>> parameters_; /*!< Separate command line parameters. @since 0.4.0 */ std::vector<std::string> parameters_; /*!< Separate command line parameters. @since 0.4.0 */
size_t escape_parameters_ = std::numeric_limits<size_t>::max(); /*!< Number of initial arguments to escape in output. @since 0.5.0 */ size_t escape_parameters_ = std::numeric_limits<size_t>::max(); /*!< Number of initial arguments to escape in output. @since 0.5.0 */
}; };
/** /**

View File

@@ -232,7 +232,7 @@ void Logger::vlog(Level level, const char * format, va_list ap) const {
} }
void Logger::vlog(Level level, Facility facility, const char * format, va_list ap) const { void Logger::vlog(Level level, Facility facility, const char * format, va_list ap) const {
std::vector<char, AllocatorPSRAM<char>> text(MAX_LOG_LENGTH + 1); std::vector<char> text(MAX_LOG_LENGTH + 1);
if (vsnprintf(text.data(), text.size(), format, ap) <= 0) { if (vsnprintf(text.data(), text.size(), format, ap) <= 0) {
return; return;
@@ -241,7 +241,7 @@ void Logger::vlog(Level level, Facility facility, const char * format, va_list a
dispatch(level, facility, text); dispatch(level, facility, text);
} }
void Logger::dispatch(Level level, Facility facility, std::vector<char, AllocatorPSRAM<char>> & text) const { void Logger::dispatch(Level level, Facility facility, std::vector<char> & text) const {
std::shared_ptr<Message> message = std::make_shared<Message>(get_uptime_ms(), level, facility, name_, text.data()); std::shared_ptr<Message> message = std::make_shared<Message>(get_uptime_ms(), level, facility, name_, text.data());
text.resize(0); text.resize(0);

View File

@@ -31,7 +31,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <esp32-psram.h>
#include <uuid/common.h> #include <uuid/common.h>
#ifndef UUID_COMMON_THREAD_SAFE #ifndef UUID_COMMON_THREAD_SAFE
@@ -646,7 +645,7 @@ class Logger {
* @param[in] text Log message text. * @param[in] text Log message text.
* @since 1.0.0 * @since 1.0.0
*/ */
void dispatch(Level level, Facility facility, std::vector<char, AllocatorPSRAM<char>> & text) const; void dispatch(Level level, Facility facility, std::vector<char> & text) const;
static std::atomic<Level> global_level_; /*!< Minimum global log level across all handlers. @since 3.0.0 */ static std::atomic<Level> global_level_; /*!< Minimum global log level across all handlers. @since 3.0.0 */
#if UUID_LOG_THREAD_SAFE #if UUID_LOG_THREAD_SAFE
@@ -724,7 +723,7 @@ class PrintHandler : public uuid::log::Handler {
mutable std::mutex mutex_; /*!< Mutex for configuration, state and queued log messages. @since 2.3.0 */ mutable std::mutex mutex_; /*!< Mutex for configuration, state and queued log messages. @since 2.3.0 */
#endif #endif
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 2.2.0 */ size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 2.2.0 */
std::list<std::shared_ptr<Message>, AllocatorPSRAM<std::shared_ptr<Message>>> log_messages_; /*!< Queued log messages, in the order they were received. @since 2.2.0 */ std::list<std::shared_ptr<Message>> log_messages_; /*!< Queued log messages, in the order they were received. @since 2.2.0 */
}; };
} // namespace log } // namespace log

View File

@@ -20,7 +20,7 @@
#include "../../src/core/emsesp.h" #include "../../src/core/emsesp.h"
#ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY #ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
// time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637 // time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637
#define UUID_SYSLOG_HAVE_GETTIMEOFDAY 1 #define UUID_SYSLOG_HAVE_GETTIMEOFDAY 1
#endif #endif

View File

@@ -28,7 +28,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <esp32-psram.h>
#include <uuid/log.h> #include <uuid/log.h>
#ifndef UUID_LOG_THREAD_SAFE #ifndef UUID_LOG_THREAD_SAFE
@@ -322,7 +321,7 @@ class SyslogService : public uuid::log::Handler {
#endif #endif
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 1.0.0 */ size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 1.0.0 */
unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 1.0.0 */ unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 1.0.0 */
std::list<QueuedLogMessage, AllocatorPSRAM<QueuedLogMessage>> log_messages_; /*!< Queued log messages, in the order they were received. @since 1.0.0 */ std::list<QueuedLogMessage> log_messages_; /*!< Queued log messages, in the order they were received. @since 1.0.0 */
uint64_t mark_interval_ = 0; /*!< Mark interval in milliseconds. @since 2.0.0 */ uint64_t mark_interval_ = 0; /*!< Mark interval in milliseconds. @since 2.0.0 */
uint64_t last_message_ = 0; /*!< Last message/mark time. @since 2.0.0 */ uint64_t last_message_ = 0; /*!< Last message/mark time. @since 2.0.0 */

View File

@@ -249,7 +249,7 @@ size_t TelnetStream::write(uint8_t data) {
} }
size_t TelnetStream::write(const uint8_t * buffer, size_t size) { size_t TelnetStream::write(const uint8_t * buffer, size_t size) {
std::vector<unsigned char, AllocatorPSRAM<unsigned char>> data; std::vector<unsigned char> data;
data.reserve(size); data.reserve(size);
while (size-- > 0) { while (size-- > 0) {
@@ -310,7 +310,7 @@ size_t TelnetStream::raw_write(unsigned char data) {
return 1; return 1;
} }
size_t TelnetStream::raw_write(const std::vector<unsigned char, AllocatorPSRAM<unsigned char>> & data) { size_t TelnetStream::raw_write(const std::vector<unsigned char> & data) {
return raw_write(reinterpret_cast<const unsigned char *>(data.data()), data.size()); return raw_write(reinterpret_cast<const unsigned char *>(data.data()), data.size());
} }

View File

@@ -33,7 +33,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <esp32-psram.h>
#include <uuid/console.h> #include <uuid/console.h>
namespace uuid { namespace uuid {
@@ -204,7 +203,7 @@ class TelnetStream : public ::Stream {
* @return The number of bytes that were output. * @return The number of bytes that were output.
* @since 0.1.0 * @since 0.1.0
*/ */
size_t raw_write(const std::vector<unsigned char, AllocatorPSRAM<unsigned char>> & data); size_t raw_write(const std::vector<unsigned char> & data);
/** /**
* Write an array of bytes directly to the output stream. * Write an array of bytes directly to the output stream.
* *
@@ -223,7 +222,7 @@ class TelnetStream : public ::Stream {
unsigned char previous_in_ = 0; /*!< Previous character that was received. Used to detect CR NUL. @since 0.1.0 */ unsigned char previous_in_ = 0; /*!< Previous character that was received. Used to detect CR NUL. @since 0.1.0 */
unsigned char previous_out_ = 0; /*!< Previous character that was sent. Used to insert NUL after CR without LF. @since 0.1.0 */ unsigned char previous_out_ = 0; /*!< Previous character that was sent. Used to insert NUL after CR without LF. @since 0.1.0 */
int peek_ = -1; /*!< Previously read data cached by peek(). @since 0.1.0 */ int peek_ = -1; /*!< Previously read data cached by peek(). @since 0.1.0 */
std::vector<char, AllocatorPSRAM<char>> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */ std::vector<char> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */
}; };
/** /**
@@ -426,7 +425,7 @@ class TelnetService {
WiFiServer server_; /*!< TCP server. @since 0.1.0 */ WiFiServer server_; /*!< TCP server. @since 0.1.0 */
size_t maximum_connections_ = MAX_CONNECTIONS; /*!< Maximum number of concurrent open connections. @since 0.1.0 */ size_t maximum_connections_ = MAX_CONNECTIONS; /*!< Maximum number of concurrent open connections. @since 0.1.0 */
std::list<Connection, AllocatorPSRAM<Connection>> connections_; /*!< Open connections. @since 0.1.0 */ std::list<Connection> connections_; /*!< Open connections. @since 0.1.0 */
shell_factory_function shell_factory_; /*!< Function to create a shell. @since 0.1.0 */ shell_factory_function shell_factory_; /*!< Function to create a shell. @since 0.1.0 */
unsigned long initial_idle_timeout_ = DEFAULT_IDLE_TIMEOUT; /*!< Initial idle timeout (in seconds). @since 0.1.0 */ unsigned long initial_idle_timeout_ = DEFAULT_IDLE_TIMEOUT; /*!< Initial idle timeout (in seconds). @since 0.1.0 */
unsigned long write_timeout_ = DEFAULT_WRITE_TIMEOUT; /*!< Write timeout (in milliseconds). @since 0.1.0 */ unsigned long write_timeout_ = DEFAULT_WRITE_TIMEOUT; /*!< Write timeout (in milliseconds). @since 0.1.0 */

View File

@@ -145,7 +145,6 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) {
return 0; return 0;
}; };
void ledcAttachPin(uint8_t pin, uint8_t chan) {}; void ledcAttachPin(uint8_t pin, uint8_t chan) {};
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {};
void ledcWrite(uint8_t chan, uint32_t duty) {}; void ledcWrite(uint8_t chan, uint32_t duty) {};
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {}; void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {}; void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};

View File

@@ -72,7 +72,6 @@ void analogSetAttenuation(adc_attenuation_t attenuation);
void dacWrite(uint8_t pin, uint8_t value); void dacWrite(uint8_t pin, uint8_t value);
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num); double ledcSetup(uint8_t chan, double freq, uint8_t bit_num);
void ledcAttachPin(uint8_t pin, uint8_t chan); void ledcAttachPin(uint8_t pin, uint8_t chan);
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num);
void ledcWrite(uint8_t chan, uint32_t duty); void ledcWrite(uint8_t chan, uint32_t duty);
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2026, Benoit BLANCHON // Copyright © 2014-2025, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -239,11 +239,11 @@
#define ARDUINOJSON_BIN2ALPHA_1111() P #define ARDUINOJSON_BIN2ALPHA_1111() P
#define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D() #define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D()
#define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D) #define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D)
#define ARDUINOJSON_VERSION "7.4.3" #define ARDUINOJSON_VERSION "7.4.2"
#define ARDUINOJSON_VERSION_MAJOR 7 #define ARDUINOJSON_VERSION_MAJOR 7
#define ARDUINOJSON_VERSION_MINOR 4 #define ARDUINOJSON_VERSION_MINOR 4
#define ARDUINOJSON_VERSION_REVISION 3 #define ARDUINOJSON_VERSION_REVISION 2
#define ARDUINOJSON_VERSION_MACRO V743 #define ARDUINOJSON_VERSION_MACRO V742
#ifndef ARDUINOJSON_VERSION_NAMESPACE #ifndef ARDUINOJSON_VERSION_NAMESPACE
#define ARDUINOJSON_VERSION_NAMESPACE \ #define ARDUINOJSON_VERSION_NAMESPACE \
ARDUINOJSON_CONCAT5(ARDUINOJSON_VERSION_MACRO, \ ARDUINOJSON_CONCAT5(ARDUINOJSON_VERSION_MACRO, \
@@ -1536,12 +1536,11 @@ template <typename T, size_t = sizeof(T)>
struct FloatTraits {}; struct FloatTraits {};
template <typename T> template <typename T>
struct FloatTraits<T, 8 /*64bits*/> { struct FloatTraits<T, 8 /*64bits*/> {
using mantissa_type = uint64_t; using mantissa_type = uint64_t;
static const short mantissa_bits = 52; static const short mantissa_bits = 52;
static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1;
using exponent_type = int16_t; using exponent_type = int16_t;
static const exponent_type exponent_max = 308; static const exponent_type exponent_max = 308;
static const size_t binaryPowersOfTen = 9;
static pgm_ptr<T> positiveBinaryPowersOfTen() { static pgm_ptr<T> positiveBinaryPowersOfTen() {
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
uint64_t, uint64_t,
@@ -1602,12 +1601,11 @@ struct FloatTraits<T, 8 /*64bits*/> {
}; };
template <typename T> template <typename T>
struct FloatTraits<T, 4 /*32bits*/> { struct FloatTraits<T, 4 /*32bits*/> {
using mantissa_type = uint32_t; using mantissa_type = uint32_t;
static const short mantissa_bits = 23; static const short mantissa_bits = 23;
static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1;
using exponent_type = int8_t; using exponent_type = int8_t;
static const exponent_type exponent_max = 38; static const exponent_type exponent_max = 38;
static const size_t binaryPowersOfTen = 6;
static pgm_ptr<T> positiveBinaryPowersOfTen() { static pgm_ptr<T> positiveBinaryPowersOfTen() {
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t,
factors, factors,
@@ -1670,12 +1668,9 @@ template <typename TFloat, typename TExponent>
inline TFloat make_float(TFloat m, TExponent e) { inline TFloat make_float(TFloat m, TExponent e) {
using traits = FloatTraits<TFloat>; using traits = FloatTraits<TFloat>;
auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen() : traits::negativeBinaryPowersOfTen(); auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen() : traits::negativeBinaryPowersOfTen();
auto count = traits::binaryPowersOfTen;
if (e <= 0) if (e <= 0)
e = TExponent(-e); e = TExponent(-e);
for (uint8_t index = 0; e != 0; index++) { for (uint8_t index = 0; e != 0; index++) {
if (index >= count)
return traits::nan();
if (e & 1) if (e & 1)
m *= powersOfTen[index]; m *= powersOfTen[index];
e >>= 1; e >>= 1;
@@ -2427,7 +2422,7 @@ class VariantData {
return; return;
var->removeMember(key, resources); var->removeMember(key, resources);
} }
void reset() { // TODO: remove void reset() {
type_ = VariantType::Null; type_ = VariantType::Null;
} }
void setBoolean(bool value) { void setBoolean(bool value) {
@@ -4219,7 +4214,7 @@ template <typename T, typename Enable = void>
struct Comparer; struct Comparer;
template <typename T> template <typename T>
struct Comparer<T, enable_if_t<IsString<T>::value>> : ComparerBase { struct Comparer<T, enable_if_t<IsString<T>::value>> : ComparerBase {
T rhs; // TODO: store adapted string? T rhs;
explicit Comparer(T value) explicit Comparer(T value)
: rhs(value) { : rhs(value) {
} }
@@ -5303,7 +5298,7 @@ class StringBuilder {
append(*s++); append(*s++);
} }
void append(const char * s, size_t n) { void append(const char * s, size_t n) {
while (n-- > 0) // TODO: memcpy while (n-- > 0)
append(*s++); append(*s++);
} }
void append(char c) { void append(char c) {

View File

@@ -19,164 +19,12 @@ class AsyncClient {
class AsyncServer { class AsyncServer {
public: public:
AsyncServer(uint16_t port) AsyncServer(uint16_t port)
: _port(port) {}; : _port(port){};
~AsyncServer() {}; ~AsyncServer(){};
protected: protected:
uint16_t _port; uint16_t _port;
}; };
namespace asyncsrv {
static constexpr const char empty[] = "";
static constexpr const char T__opaque[] = "\", opaque=\"";
static constexpr const char T_100_CONTINUE[] = "100-continue";
static constexpr const char T_13[] = "13";
static constexpr const char T_ACCEPT[] = "Accept";
static constexpr const char T_Accept_Ranges[] = "Accept-Ranges";
static constexpr const char T_attachment[] = "attachment; filename=\"";
static constexpr const char T_AUTH[] = "Authorization";
static constexpr const char T_auth_nonce[] = "\", qop=\"auth\", nonce=\"";
static constexpr const char T_BASIC[] = "Basic";
static constexpr const char T_BASIC_REALM[] = "Basic realm=\"";
static constexpr const char T_BEARER[] = "Bearer";
static constexpr const char T_BODY[] = "body";
static constexpr const char T_Cache_Control[] = "Cache-Control";
static constexpr const char T_chunked[] = "chunked";
static constexpr const char T_close[] = "close";
static constexpr const char T_cnonce[] = "cnonce";
static constexpr const char T_Connection[] = "Connection";
static constexpr const char T_Content_Disposition[] = "Content-Disposition";
static constexpr const char T_Content_Encoding[] = "Content-Encoding";
static constexpr const char T_Content_Length[] = "Content-Length";
static constexpr const char T_Content_Type[] = "Content-Type";
static constexpr const char T_Content_Location[] = "Content-Location";
static constexpr const char T_Cookie[] = "Cookie";
static constexpr const char T_CORS_ACAC[] = "Access-Control-Allow-Credentials";
static constexpr const char T_CORS_ACAH[] = "Access-Control-Allow-Headers";
static constexpr const char T_CORS_ACAM[] = "Access-Control-Allow-Methods";
static constexpr const char T_CORS_ACAO[] = "Access-Control-Allow-Origin";
static constexpr const char T_CORS_ACMA[] = "Access-Control-Max-Age";
static constexpr const char T_CORS_O[] = "Origin";
static constexpr const char T_data_[] = "data: ";
static constexpr const char T_Date[] = "Date";
static constexpr const char T_DIGEST[] = "Digest";
static constexpr const char T_DIGEST_[] = "Digest ";
static constexpr const char T_ETag[] = "ETag";
static constexpr const char T_event_[] = "event: ";
static constexpr const char T_EXPECT[] = "Expect";
static constexpr const char T_FALSE[] = "false";
static constexpr const char T_filename[] = "filename";
static constexpr const char T_gzip[] = "gzip";
static constexpr const char T_Host[] = "host";
static constexpr const char T_HTTP_1_0[] = "HTTP/1.0";
static constexpr const char T_HTTP_100_CONT[] = "HTTP/1.1 100 Continue\r\n\r\n";
static constexpr const char T_id__[] = "id: ";
static constexpr const char T_IMS[] = "If-Modified-Since";
static constexpr const char T_INM[] = "If-None-Match";
static constexpr const char T_inline[] = "inline";
static constexpr const char T_keep_alive[] = "keep-alive";
static constexpr const char T_Last_Event_ID[] = "Last-Event-ID";
static constexpr const char T_Last_Modified[] = "Last-Modified";
static constexpr const char T_LOCATION[] = "Location";
static constexpr const char T_LOGIN_REQ[] = "Login Required";
static constexpr const char T_MULTIPART_[] = "multipart/";
static constexpr const char T_name[] = "name";
static constexpr const char T_nc[] = "nc";
static constexpr const char T_no_cache[] = "no-cache";
static constexpr const char T_nonce[] = "nonce";
static constexpr const char T_none[] = "none";
static constexpr const char T_opaque[] = "opaque";
static constexpr const char T_qop[] = "qop";
static constexpr const char T_realm[] = "realm";
static constexpr const char T_realm__[] = "realm=\"";
static constexpr const char T_response[] = "response";
static constexpr const char T_retry_[] = "retry: ";
static constexpr const char T_retry_after[] = "Retry-After";
static constexpr const char T_nn[] = "\n\n";
static constexpr const char T_rn[] = "\r\n";
static constexpr const char T_rnrn[] = "\r\n\r\n";
static constexpr const char T_Server[] = "Server";
static constexpr const char T_Transfer_Encoding[] = "Transfer-Encoding";
static constexpr const char T_TRUE[] = "true";
static constexpr const char T_UPGRADE[] = "Upgrade";
static constexpr const char T_uri[] = "uri";
static constexpr const char T_username[] = "username";
static constexpr const char T_WS[] = "websocket";
static constexpr const char T_WWW_AUTH[] = "WWW-Authenticate";
// HTTP Methods
static constexpr const char T_ANY[] = "ANY";
static constexpr const char T_GET[] = "GET";
static constexpr const char T_POST[] = "POST";
static constexpr const char T_PUT[] = "PUT";
static constexpr const char T_DELETE[] = "DELETE";
static constexpr const char T_PATCH[] = "PATCH";
static constexpr const char T_HEAD[] = "HEAD";
static constexpr const char T_OPTIONS[] = "OPTIONS";
static constexpr const char T_UNKNOWN[] = "UNKNOWN";
// Req content types
static constexpr const char T_RCT_NOT_USED[] = "RCT_NOT_USED";
static constexpr const char T_RCT_DEFAULT[] = "RCT_DEFAULT";
static constexpr const char T_RCT_HTTP[] = "RCT_HTTP";
static constexpr const char T_RCT_WS[] = "RCT_WS";
static constexpr const char T_RCT_EVENT[] = "RCT_EVENT";
static constexpr const char T_ERROR[] = "ERROR";
// extensions & MIME-Types
static constexpr const char T__avif[] = ".avif"; // AVIF: Highly compressed images. Compatible with all modern browsers.
static constexpr const char T__csv[] = ".csv"; // CSV: Data logging and configuration
static constexpr const char T__css[] = ".css"; // CSS: Styling for web interfaces
static constexpr const char T__gif[] = ".gif"; // GIF: Simple animations. Legacy support
static constexpr const char T__gz[] = ".gz"; // GZ: compressed files
static constexpr const char T__htm[] = ".htm"; // HTM: Web interface files
static constexpr const char T__html[] = ".html"; // HTML: Web interface files
static constexpr const char T__ico[] = ".ico"; // ICO: Favicons, system icons. Legacy support
static constexpr const char T__jpg[] = ".jpg"; // JPEG/JPG: Photos. Legacy support
static constexpr const char T__js[] = ".js"; // JavaScript: Interactive functionality
static constexpr const char T__json[] = ".json"; // JSON: Data exchange format
static constexpr const char T__mp4[] = ".mp4"; // MP4: Proprietary format. Worse compression than WEBM.
static constexpr const char T__mjs[] = ".mjs"; // MJS: JavaScript module format
static constexpr const char T__opus[] = ".opus"; // OPUS: High compression audio format
static constexpr const char T__pdf[] = ".pdf"; // PDF: Universal document format
static constexpr const char T__png[] = ".png"; // PNG: Icons, logos, transparency. Legacy support
static constexpr const char T__svg[] = ".svg"; // SVG: Vector graphics, icons (scalable, tiny file sizes)
static constexpr const char T__ttf[] = ".ttf"; // TTF: Font file. Legacy support
static constexpr const char T__txt[] = ".txt"; // TXT: Plain text files
static constexpr const char T__webm[] = ".webm"; // WebM: Video. Open source, optimized for web. Compatible with all modern browsers.
static constexpr const char T__webp[] = ".webp"; // WebP: Highly compressed images. Compatible with all modern browsers.
static constexpr const char T__woff[] = ".woff"; // WOFF: Font file. Legacy support
static constexpr const char T__woff2[] = ".woff2"; // WOFF2: Better compression. Compatible with all modern browsers.
static constexpr const char T__xml[] = ".xml"; // XML: Configuration and data files
static constexpr const char T_application_javascript[] = "application/javascript"; // Obsolete type for JavaScript
static constexpr const char T_application_json[] = "application/json";
static constexpr const char T_application_msgpack[] = "application/msgpack";
static constexpr const char T_application_octet_stream[] = "application/octet-stream";
static constexpr const char T_application_pdf[] = "application/pdf";
static constexpr const char T_app_xform_urlencoded[] = "application/x-www-form-urlencoded";
static constexpr const char T_audio_opus[] = "audio/opus";
static constexpr const char T_font_ttf[] = "font/ttf";
static constexpr const char T_font_woff[] = "font/woff";
static constexpr const char T_font_woff2[] = "font/woff2";
static constexpr const char T_image_avif[] = "image/avif";
static constexpr const char T_image_gif[] = "image/gif";
static constexpr const char T_image_jpeg[] = "image/jpeg";
static constexpr const char T_image_png[] = "image/png";
static constexpr const char T_image_svg_xml[] = "image/svg+xml";
static constexpr const char T_image_webp[] = "image/webp";
static constexpr const char T_image_x_icon[] = "image/x-icon";
static constexpr const char T_text_css[] = "text/css";
static constexpr const char T_text_csv[] = "text/csv";
static constexpr const char T_text_event_stream[] = "text/event-stream";
static constexpr const char T_text_html[] = "text/html";
static constexpr const char T_text_javascript[] = "text/javascript";
static constexpr const char T_text_plain[] = "text/plain";
static constexpr const char T_text_xml[] = "text/xml";
static constexpr const char T_video_mp4[] = "video/mp4";
static constexpr const char T_video_webm[] = "video/webm";
} // namespace asyncsrv
#endif #endif

View File

@@ -67,9 +67,6 @@ class Preferences {
size_t putString(const char * key, String value) { size_t putString(const char * key, String value) {
return 0; return 0;
} }
bool isKey(const char * key) {
return true;
}
// unused.... // unused....
@@ -87,6 +84,7 @@ class Preferences {
// size_t putBool(const char * key, bool value); // size_t putBool(const char * key, bool value);
// size_t putBytes(const char * key, const void * value, size_t len); // size_t putBytes(const char * key, const void * value, size_t len);
// bool isKey(const char * key);
// PreferenceType getType(const char * key); // PreferenceType getType(const char * key);
// int8_t getChar(const char * key, int8_t defaultValue = 0); // int8_t getChar(const char * key, int8_t defaultValue = 0);
// int16_t getShort(const char * key, int16_t defaultValue = 0); // int16_t getShort(const char * key, int16_t defaultValue = 0);

Some files were not shown because too many files have changed in this diff Show More