This commit is contained in:
proddy
2024-11-29 10:30:05 +01:00
161 changed files with 15515 additions and 12248 deletions

132
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@@ -0,0 +1,132 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -21,7 +21,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://docs.emsesp.org/Troubleshooting/)
- [ ] Searched the issue in the [chat](https://discord.gg/3J3GgnzpyT) - [ ] 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`

View File

@@ -1,7 +1,7 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: EMS-ESP Docs - name: EMS-ESP Docs
url: https://emsesp.org url: https://docs.emsesp.org
about: All the information related to EMS-ESP. about: All the information related to EMS-ESP.
- name: EMS-ESP Discussions and Support - name: EMS-ESP Discussions and Support
url: https://github.com/emsesp/EMS-ESP32/discussions url: https://github.com/emsesp/EMS-ESP32/discussions

1
.github/SUPPORT.md vendored Normal file
View File

@@ -0,0 +1 @@
# Support

37
.github/workflows/pr_check.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: 'pr_check'
on:
workflow_dispatch:
pull_request:
branches: dev
paths:
- '**.c'
- '**.cpp'
- '**.h'
- '**.hpp'
- '**.json'
- '**.py'
- '**.md'
- '.github/workflows/pr_check.yml'
jobs:
pre-release:
name: 'Automatic pre-release build'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install PlatformIO
run: |
pip install wheel
pip install -U platformio
- name: Build native
run: |
platformio run -e native

10
.gitignore vendored
View File

@@ -30,13 +30,8 @@ stats.html
*.sln *.sln
*.sw? *.sw?
.pnp.* .pnp.*
*/.yarn/* */.yarn/cache/*
!.yarn/patches */.yarn/install-state.gz
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
yarn.lock
analyse.html analyse.html
interface/vite.config.ts.timestamp* interface/vite.config.ts.timestamp*
*.local *.local
@@ -71,4 +66,3 @@ words-found-verbose.txt
# sonarlint # sonarlint
compile_commands.json compile_commands.json
package.json

6
.markdownlint.json Normal file
View File

@@ -0,0 +1,6 @@
{
"MD033": false,
"MD013": false,
"MD045": false,
"MD041": false
}

View File

@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.7.0] October 27 2024 ## [3.7.0] 27 October 2024
## **IMPORTANT! BREAKING CHANGES with 3.6.5** ## **IMPORTANT! BREAKING CHANGES with 3.6.5**
@@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The automatically generated temperature sensor ID has replaced dashes (`-`) with underscores (`_`) to be compatible with Home Assistant. - The automatically generated temperature sensor ID has replaced dashes (`-`) with underscores (`_`) to be compatible with Home Assistant.
- `api/system/info` has it's JSON key names changed to camelCase syntax. - `api/system/info` has it's JSON key names changed to camelCase syntax.
For more details go to [www.emsesp.org](https://www.emsesp.org/). For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
## Added ## Added

View File

@@ -1 +1,34 @@
# Changelog # Changelog
For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
## [3.7.1]
## **IMPORTANT! BREAKING CHANGES since v3.7.0**
## Added
- include HA "unit_of_meas", "stat_cla" and "dev_cla" attributes for Number sensors [#2149](https://github.com/emsesp/EMS-ESP32/issues/2149)
- Bosch CS6800i AW - Silent Mode + Electrical Power Reduction (HP) [#2147](https://github.com/emsesp/EMS-ESP32/issues/2147)
- `/api/system/showeralert` and `/api/system/showertimer` [#2182](https://github.com/emsesp/EMS-ESP32/issues/2182)
- MX400 [#2198](https://github.com/emsesp/EMS-ESP32/issues/2198)
- SM200 values [#2212](https://github.com/emsesp/EMS-ESP32/discussions/2212)
## Fixed
- Modbus integration in 3.7.0 missing offset [#2148](https://github.com/emsesp/EMS-ESP32/issues/2148)
- fix changing TZ in NTPsettings without clearing enable+server, added DST support [#2142](https://github.com/emsesp/EMS-ESP32/issues/2142)
- Support MQTT Discovery (AD) with Domoticz [#2177](https://github.com/emsesp/EMS-ESP32/issues/2177)
- wwExtra (dhw extra) changed from temperature reading to number
- auxheaterstatus [#2192](https://github.com/emsesp/EMS-ESP32/issues/2192)
- lastCode character check [#2189](https://github.com/emsesp/EMS-ESP32/issues/2189)
- reading too many telegram parts
- heatpump cost UOMs [#2188](https://github.com/emsesp/EMS-ESP32/issues/2188)
- analog dac output and inputs on dac pins [#2201](https://github.com/emsesp/EMS-ESP32/discussions/2201)
- api memory leak [#2216](https://github.com/emsesp/EMS-ESP32/issues/2216)
- modbus multiple mixers [#2229](https://github.com/emsesp/EMS-ESP32/issues/2229)
- Last Will (LWT) not set on MQTT Connect [#2247](https://github.com/emsesp/EMS-ESP32/issues/2247)
## Changed
- name of wwstarts2 [#2217](https://github.com/emsesp/EMS-ESP32/discussions/2217)

View File

@@ -6,7 +6,7 @@ Everybody is welcome and invited to contribute to the EMS-ESP Project by:
- providing Pull Requests (Features, Fixes, suggestions) - providing Pull Requests (Features, Fixes, suggestions)
- testing new released features and report issues on your EMS equipment - testing new released features and report issues on your EMS equipment
- contributing to missing [documentation](https://emsesp.org) - contributing to missing [documentation](https://docs.emsesp.org)
This document describes rules that are in effect for this repository, meant for handling issues by contributors in the issue tracker and PRs. This document describes rules that are in effect for this repository, meant for handling issues by contributors in the issue tracker and PRs.

View File

@@ -1,10 +1,27 @@
# #
# GNUMakefile for EMS-ESP # GNUMakefile for EMS-ESP
# This is mainly used to generate the .o files for SonarQube analysis
# #
# NUMJOBS=${NUMJOBS:-" -j10 "} _mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
# MAKEFLAGS+="j " I := $(patsubst %/,%,$(dir $(_mkfile_path)))
ifneq ($(words $(MAKECMDGOALS)),1)
.DEFAULT_GOAL = all
%:
@$(MAKE) $@ --no-print-directory -rRf $(firstword $(MAKEFILE_LIST))
else
ifndef ECHO
T := $(shell $(MAKE) $(MAKECMDGOALS) --no-print-directory \
-nrRf $(firstword $(MAKEFILE_LIST)) \
ECHO="COUNTTHIS" | grep -c "COUNTTHIS")
N := x
C = $(words $N)$(eval N := x $N)
ECHO = python $(I)/echo_progress.py --stepno=$C --nsteps=$T
endif
# number of parallel compiles
JOBS ?= $(shell nproc)
MAKEFLAGS += -j $(JOBS) -l $(JOBS)
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Project Structure # Project Structure
@@ -43,7 +60,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO
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 += $(ARGS) DEFINES += $(ARGS)
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.1-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S3\"
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Sources & Files # Sources & Files
@@ -125,23 +142,27 @@ COMPILE.cpp = $(CXX) $(CXX_STANDARD) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
.SILENT: $(OUTPUT) .SILENT: $(OUTPUT)
all: $(OUTPUT) all: $(OUTPUT)
@$(ECHO) All done
$(OUTPUT): $(OBJS) $(OUTPUT): $(OBJS)
@mkdir -p $(@D) @mkdir -p $(@D)
@$(ECHO) Linking $@
$(LINK.o) $(LINK.o)
$(SYMBOLS.out) $(SYMBOLS.out)
$(BUILD)/%.o: %.c $(BUILD)/%.o: %.c
@mkdir -p $(@D) @mkdir -p $(@D)
$(COMPILE.c) @$(ECHO) Compiling $@
@$(COMPILE.c)
$(BUILD)/%.o: %.cpp $(BUILD)/%.o: %.cpp
@mkdir -p $(@D) @mkdir -p $(@D)
$(COMPILE.cpp) @$(ECHO) Compiling $@
@$(COMPILE.cpp)
$(BUILD)/%.o: %.s $(BUILD)/%.o: %.s
@mkdir -p $(@D) @mkdir -p $(@D)
$(COMPILE.s) @$(COMPILE.s)
cppcheck: $(SOURCES) cppcheck: $(SOURCES)
$(CPPCHECK) $(CHECKFLAGS) $^ $(CPPCHECK) $(CHECKFLAGS) $^
@@ -150,6 +171,7 @@ run: $(OUTPUT)
@$< @$<
.PHONY: clean .PHONY: clean
clean: clean:
@$(RM) -rf $(BUILD) $(OUTPUT) @$(RM) -rf $(BUILD) $(OUTPUT)
@@ -157,4 +179,6 @@ help:
@echo available targets: all run clean @echo available targets: all run clean
@echo $(OUTPUT) @echo $(OUTPUT)
-include $(DEPS) -include $(DEPS)
endif

View File

@@ -1,4 +1,30 @@
# ![logo](media/EMS-ESP_logo_dark.png) <div align="center">
<p align="center">
<a href="#">
<img src="https://raw.githubusercontent.com/emsesp/EMS-ESP32/dev/media/favicon/android-chrome-512x512.png" height="100px" />
</a>
</p>
</div>
<h1 align="center">EMS-ESP</h1>
<p align="center">
<a href="https://emsesp.org">
<img src="https://img.shields.io/badge/Website-0077b5?style=for-the-badge&logo=googlehome&logoColor=white" alt="Website" />
</a>
<a href="https://github.com/emsesp/EMS-ESP32/blob/dev/CONTRIBUTING.md">
<img src="https://img.shields.io/badge/Contribute-ff4785?style=for-the-badge&logo=git&logoColor=white" alt="Contribute" />
</a>
<a href="https://docs.emsesp.org">
<img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" />
</a>
<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" />
</a>
<a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md">
<img src="https://img.shields.io/badge/Changelog-6c5ce7?style=for-the-badge&logo=git&logoColor=white" alt="Changelog" />
</a>
</p>
[![version](https://img.shields.io/github/release/emsesp/EMS-ESP32.svg?label=Latest%20Release)](https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md) [![version](https://img.shields.io/github/release/emsesp/EMS-ESP32.svg?label=Latest%20Release)](https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md)
[![release-date](https://img.shields.io/github/release-date/emsesp/EMS-ESP32.svg?label=Released)](https://github.com/emsesp/EMS-ESP32/commits/main) [![release-date](https://img.shields.io/github/release-date/emsesp/EMS-ESP32.svg?label=Released)](https://github.com/emsesp/EMS-ESP32/commits/main)
@@ -16,7 +42,7 @@
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl> or custom built. It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl> or custom built.
## **Key Features** ## 📦&nbsp; **Key Features**
- Compatible with EMS, EMS+, EMS2, EMS Plus, Logamatic EMS, Junkers 2-wire, Heatronic 3 and 4 - Compatible with EMS, EMS+, EMS2, EMS Plus, Logamatic EMS, Junkers 2-wire, Heatronic 3 and 4
- Supporting over 120 different EMS compatible devices such as thermostats, boilers, heat pumps, mixing units, solar modules, connect modules, ventilation units, switches and more - Supporting over 120 different EMS compatible devices such as thermostats, boilers, heat pumps, mixing units, solar modules, connect modules, ventilation units, switches and more
@@ -32,35 +58,31 @@ It requires a small circuit to interface with the EMS bus which can be purchased
- A powerful Scheduler to automate tasks and trigger events based data changes - A powerful Scheduler to automate tasks and trigger events based data changes
- A Notification service to alert you of important events - A Notification service to alert you of important events
## **Installing** ## 🚀&nbsp; **Installing**
For a quick install of the latest stable release go to [https://install.emsesp.org](https://install.emsesp.org). For other methods of installing and upgrading, and switching over to the development version go to [this section](https://emsesp.org/Getting-Started/#first-time-install) in the documentation. Head over to [download.emsesp.org](https://download.emsesp.org) for instructions on how to install EMS-ESP. There is also further details on which boards are supported in [this section](https://docs.emsesp.org/Getting-Started/#first-time-install) of the documentation.
If you're upgrading a BBQKees Electronics EMS Gateway and unsure which firmware to use, please refer to the [this overview](https://emsesp.org/Getting-Started/#bbqkees-electronics-ems-gateway). ## 📋&nbsp; **Documentation**
## **Documentation** Visit [emsesp.org](https://docs.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.
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**
## **Getting Support**
To chat with the community reach out on our [Discord Server](https://discord.gg/3J3GgnzpyT). 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 [here](https://emsesp.org/Support/) on how to submit a bug report or feature request. If you find an issue or have a request, see [here](https://docs.emsesp.org/Support/) on how to submit a bug report or feature request.
## **Live Demo** ## 🎥&nbsp; **Live Demo**
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. 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.
## **Contributors** ## 💖&nbsp; **Contributors**
EMS-ESP is a project created by [proddy](https://github.com/proddy) and owned and maintained by both [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP) with support from [BBQKees Electronics](https://bbqkees-electronics.nl). EMS-ESP is a project created by [proddy](https://github.com/proddy) and owned and maintained by both [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP) with support from [BBQKees Electronics](https://bbqkees-electronics.nl).
You can contact us using [this form](https://emsesp.org/Contact/).
If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated. If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated.
## **Libraries used** ## 📢&nbsp; **Libraries used**
- [esp8266-react](https://github.com/rjwats/esp8266-react) by @rjwats for the core framework that provides the Web UI, which has been heavily modified - [esp8266-react](https://github.com/rjwats/esp8266-react) by @rjwats for the core framework that provides the Web UI, which has been heavily modified
- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these awesome open source libraries - [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these awesome open source libraries
@@ -68,7 +90,7 @@ If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it
- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client - [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client
- ESPAsyncWebServer and AsyncTCP for the Web server and TCP backends, with custom modifications for performance - ESPAsyncWebServer and AsyncTCP for the Web server and TCP backends, with custom modifications for performance
## **License** ## 📜&nbsp; **License**
This program is licensed under GPL-3.0 This program is licensed under GPL-3.0

View File

@@ -9,5 +9,25 @@
} }
], ],
"dictionaries": ["project-words"], "dictionaries": ["project-words"],
"ignorePaths": ["node_modules", "compile_commands.json", "WWWData.h", "**/venv/**", "lib/eModbus", "lib/ESPAsyncWebServer", "lib/espMqttClient", "analyse.html", "dist", "**/*.csv", "locale_translations.h", "TZ.tsx", "**/*.txt","build/**", "**/i18n/**", "/project-words.txt"] "ignorePaths": [
"node_modules",
"compile_commands.json",
"WWWData.h", "**/venv/**",
"lib/eModbus",
"lib/ESPAsyncWebServer",
"lib/espMqttClient",
"analyse.html",
"dist",
"**/*.csv",
"**/*.md",
"**/*.py",
"locale_translations.h",
"TZ.tsx",
"**/*.txt",
"build/**",
"**/i18n/**",
"/project-words.txt",
"Makefile",
"src/modbus_entity_parameters.hpp"
]
} }

85
data/pre_load.json Normal file
View File

@@ -0,0 +1,85 @@
{
"type": "settings",
"Network": {
"ssid": "my_wifi_ssid",
"bssid": "",
"password": "my_wifi_password",
"hostname": "ems-esp"
},
"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": "127.0.0.1",
"port": 1883,
"base": "ems-esp",
"username": "username",
"password": "password",
"client_id": "ems-esp",
"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,
"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": {
"board_profile": "S3",
"locale": "en",
"tx_mode": 1,
"ems_bus_id": 11,
"boiler_heatingoff": false,
"hide_led": true,
"telnet_enabled": true,
"notoken_api": false,
"analog_enabled": true,
"fahrenheit": false,
"bool_format": 1,
"bool_dashboard": 1,
"enum_format": 1
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ telegram_type_id,name,is_fetched
0x3B,Energy, 0x3B,Energy,
0x3D,RC35Set, 0x3D,RC35Set,
0x3E,RC35Monitor, 0x3E,RC35Monitor,
0x3F,RC35Timer, 0x3F,RC30Timer,
0x40,RC30Temp, 0x40,RC30Temp,
0x41,RC30Monitor, 0x41,RC30Monitor,
0x42,RC35Timer2, 0x42,RC35Timer2,
@@ -75,6 +75,8 @@ telegram_type_id,name,is_fetched
0x0104,ISM2StatusMessage, 0x0104,ISM2StatusMessage,
0x010C,IPMStatusMessage, 0x010C,IPMStatusMessage,
0x011E,IPMTempMessage, 0x011E,IPMTempMessage,
0x012E,HPEnergy1,
0x013B,HPEnergy2,
0x0165,JunkersSet, 0x0165,JunkersSet,
0x0166,JunkersSet, 0x0166,JunkersSet,
0x0167,JunkersSet, 0x0167,JunkersSet,
@@ -107,7 +109,7 @@ telegram_type_id,name,is_fetched
0x02A2,RC300Curves, 0x02A2,RC300Curves,
0x02A5,RC300Monitor, 0x02A5,RC300Monitor,
0x02A6,RC300Monitor, 0x02A6,RC300Monitor,
0x02A7,RC300Monitor, 0x02A7,CRFMonitor,
0x02A8,RC300Monitor, 0x02A8,RC300Monitor,
0x02A9,RC300Monitor, 0x02A9,RC300Monitor,
0x02AA,RC300Monitor, 0x02AA,RC300Monitor,
@@ -129,20 +131,20 @@ telegram_type_id,name,is_fetched
0x02BE,RC300Set, 0x02BE,RC300Set,
0x02BF,RC300Set, 0x02BF,RC300Set,
0x02C0,RC300Set, 0x02C0,RC300Set,
0x02CC,RC300Set2, 0x02CC,HPPressure,fetched
0x02CD,MMPLUSConfigMessage,fetched 0x02CD,MMPLUSConfigMessage,fetched
0x02CE,RC300Set2, 0x02CE,RC300Set2,
0x02D0,RC300Set2, 0x02D0,RC300Set2,
0x02D2,RC300Set2, 0x02D2,RC300Set2,
0x02D5,MMPLUSConfigMessage,fetched
0x02D6,HPPump2,fetched 0x02D6,HPPump2,fetched
0x02D7,MMPLUSStatusMessage, 0x02D7,MMPLUSStatusMessage,
0x02DF,MMPLUSStatusMessage,
0x02F5,RC300WWmode,fetched 0x02F5,RC300WWmode,fetched
0x02F6,RC300WW2mode,fetched 0x02F6,RC300WW2mode,fetched
0x0313,MMPLUSConfigMessage_WWC,fetched
0x031B,RC300WWtemp,fetched 0x031B,RC300WWtemp,fetched
0x031D,RC300WWmode2, 0x031D,RC300WWmode2,
0x031E,RC300WWmode2, 0x031E,RC300WWmode2,
0x0331,MMPLUSStatusMessage_WWC,
0x0358,SM100SystemConfig,fetched 0x0358,SM100SystemConfig,fetched
0x035A,SM100CircuitConfig,fetched 0x035A,SM100CircuitConfig,fetched
0x035C,SM100HeatAssist,fetched 0x035C,SM100HeatAssist,fetched
@@ -199,6 +201,15 @@ telegram_type_id,name,is_fetched
0x05D9,Airquality, 0x05D9,Airquality,
0x0772,HIUSettings, 0x0772,HIUSettings,
0x0779,HIUMonitor, 0x0779,HIUMonitor,
0x07A5,SM100wwCirc,fetched
0x07A6,SM100wwParam,fetched
0x07AA,SM100wwStatus,
0x07AB,SM100wwCommand,
0x07AC,SM100wwParam1,
0x07AD,SM100ValveStatus,
0x07AE,SM100wwKeepWarm,fetched
0x07D6,SM100wwTemperature,
0x07E0,SM100wwStatus2,fetched
0x0935,EM100SetMessage,fetched 0x0935,EM100SetMessage,fetched
0x0936,EM100OutMessage, 0x0936,EM100OutMessage,
0x0937,EM100TempMessage, 0x0937,EM100TempMessage,
@@ -207,6 +218,7 @@ telegram_type_id,name,is_fetched
0x093A,EM100ConfigMessage, 0x093A,EM100ConfigMessage,
0x0998,HPSettings,fetched 0x0998,HPSettings,fetched
0x0999,HPFunctionTest,fetched 0x0999,HPFunctionTest,fetched
0x099A,HPStarts,
0x099B,HPFlowTemp, 0x099B,HPFlowTemp,
0x099C,HPComp, 0x099C,HPComp,
0x09A0,HPTemperature, 0x09A0,HPTemperature,
1 telegram_type_id name is_fetched
29 0x3B Energy
30 0x3D RC35Set
31 0x3E RC35Monitor
32 0x3F RC35Timer RC30Timer
33 0x40 RC30Temp
34 0x41 RC30Monitor
35 0x42 RC35Timer2
75 0x0104 ISM2StatusMessage
76 0x010C IPMStatusMessage
77 0x011E IPMTempMessage
78 0x012E HPEnergy1
79 0x013B HPEnergy2
80 0x0165 JunkersSet
81 0x0166 JunkersSet
82 0x0167 JunkersSet
109 0x02A2 RC300Curves
110 0x02A5 RC300Monitor
111 0x02A6 RC300Monitor
112 0x02A7 RC300Monitor CRFMonitor
113 0x02A8 RC300Monitor
114 0x02A9 RC300Monitor
115 0x02AA RC300Monitor
131 0x02BE RC300Set
132 0x02BF RC300Set
133 0x02C0 RC300Set
134 0x02CC RC300Set2 HPPressure fetched
135 0x02CD MMPLUSConfigMessage fetched
136 0x02CE RC300Set2
137 0x02D0 RC300Set2
138 0x02D2 RC300Set2
0x02D5 MMPLUSConfigMessage fetched
139 0x02D6 HPPump2 fetched
140 0x02D7 MMPLUSStatusMessage
0x02DF MMPLUSStatusMessage
141 0x02F5 RC300WWmode fetched
142 0x02F6 RC300WW2mode fetched
143 0x0313 MMPLUSConfigMessage_WWC fetched
144 0x031B RC300WWtemp fetched
145 0x031D RC300WWmode2
146 0x031E RC300WWmode2
147 0x0331 MMPLUSStatusMessage_WWC
148 0x0358 SM100SystemConfig fetched
149 0x035A SM100CircuitConfig fetched
150 0x035C SM100HeatAssist fetched
201 0x05D9 Airquality
202 0x0772 HIUSettings
203 0x0779 HIUMonitor
204 0x07A5 SM100wwCirc fetched
205 0x07A6 SM100wwParam fetched
206 0x07AA SM100wwStatus
207 0x07AB SM100wwCommand
208 0x07AC SM100wwParam1
209 0x07AD SM100ValveStatus
210 0x07AE SM100wwKeepWarm fetched
211 0x07D6 SM100wwTemperature
212 0x07E0 SM100wwStatus2 fetched
213 0x0935 EM100SetMessage fetched
214 0x0936 EM100OutMessage
215 0x0937 EM100TempMessage
218 0x093A EM100ConfigMessage
219 0x0998 HPSettings fetched
220 0x0999 HPFunctionTest fetched
221 0x099A HPStarts
222 0x099B HPFlowTemp
223 0x099C HPComp
224 0x09A0 HPTemperature

28
echo_progress.py Normal file
View File

@@ -0,0 +1,28 @@
"""
Print makefile progress
From https://stackoverflow.com/questions/451413/make-makefile-progress-indication
"""
import argparse
import math
import sys
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--stepno", type=int, required=True)
parser.add_argument("--nsteps", type=int, required=True)
parser.add_argument("remainder", nargs=argparse.REMAINDER)
args = parser.parse_args()
nchars = int(math.log(args.nsteps, 10)) + 1
fmt_str = "[{:Xd}/{:Xd}]({:6.2f}%)".replace("X", str(nchars))
progress = 100 * args.stepno / args.nsteps
sys.stdout.write(fmt_str.format(args.stepno, args.nsteps, progress))
for item in args.remainder:
sys.stdout.write(" ")
sys.stdout.write(item)
sys.stdout.write("\n")
if __name__ == "__main__":
main()

934
interface/.yarn/releases/yarn-4.5.3.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,3 @@
nodeLinker: node-modules nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.5.3.cjs

View File

@@ -1,6 +1,6 @@
{ {
"name": "EMS-ESP", "name": "EMS-ESP",
"version": "3.7.0", "version": "3.7.1",
"description": "EMS-ESP WebUI", "description": "EMS-ESP WebUI",
"homepage": "https://emsesp.org", "homepage": "https://emsesp.org",
"author": "proddy, emsesp.org", "author": "proddy, emsesp.org",
@@ -12,56 +12,55 @@
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted", "build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-rest\" \"vite preview\"", "preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"yarn:mock-rest\" \"vite preview\"",
"mock-rest": "bun --watch ../mock-api/rest_server.ts", "mock-rest": "bun --watch ../mock-api/rest_server.ts",
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-rest\" \"vite\"", "standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"yarn:mock-rest\" \"vite\"",
"typesafe-i18n": "typesafe-i18n --no-watch", "typesafe-i18n": "typesafe-i18n --no-watch",
"webUI": "node progmem-generator.js", "webUI": "node progmem-generator.js",
"format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'", "format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'",
"lint": "eslint . --fix" "lint": "eslint . --fix"
}, },
"dependencies": { "dependencies": {
"@alova/adapter-xhr": "2.0.9", "@alova/adapter-xhr": "2.0.10",
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.5",
"@mui/icons-material": "^6.1.5", "@mui/icons-material": "^6.1.9",
"@mui/material": "^6.1.5", "@mui/material": "^6.1.9",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"alova": "3.1.1", "alova": "3.2.5",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"preact": "^10.24.3", "preact": "^10.25.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-icons": "^5.3.0", "react-icons": "^5.3.0",
"react-router-dom": "^6.27.0", "react-router": "^7.0.1",
"react-toastify": "^10.0.6", "react-toastify": "^10.0.6",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.6.3" "typescript": "^5.7.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.0", "@babel/core": "^7.26.0",
"@eslint/js": "^9.13.0", "@eslint/js": "^9.15.0",
"@preact/compat": "^18.3.1", "@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.9.1", "@preact/preset-vite": "^2.9.2",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/formidable": "^3", "@types/formidable": "^3",
"@types/node": "^22.8.1", "@types/node": "^22.10.1",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@types/react-router-dom": "^5.3.3", "concurrently": "^9.1.0",
"concurrently": "^9.0.1", "eslint": "^9.15.0",
"eslint": "^9.13.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"formidable": "^3.5.2", "formidable": "^3.5.2",
"prettier": "^3.3.3", "prettier": "^3.4.1",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.36.0", "terser": "^5.36.0",
"typescript-eslint": "8.11.0", "typescript-eslint": "8.16.0",
"vite": "^5.4.10", "vite": "^6.0.1",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.0.1" "vite-tsconfig-paths": "^5.1.3"
}, },
"packageManager": "yarn@4.5.1" "packageManager": "yarn@4.5.3"
} }

View File

@@ -1,5 +1,5 @@
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import AuthenticatedRouting from 'AuthenticatedRouting'; import AuthenticatedRouting from 'AuthenticatedRouting';

View File

@@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router';
import CustomEntities from 'app/main/CustomEntities'; import CustomEntities from 'app/main/CustomEntities';
import Customizations from 'app/main/Customizations'; import Customizations from 'app/main/Customizations';

View File

@@ -57,7 +57,10 @@ export const alovaInstance = createAlova({
}); });
export const alovaInstanceGH = createAlova({ export const alovaInstanceGH = createAlova({
baseURL: 'https://api.github.com/repos/emsesp/EMS-ESP32/releases', baseURL:
process.env.NODE_ENV === 'development'
? '/gh'
: 'https://api.github.com/repos/emsesp/EMS-ESP32/releases',
statesHook: ReactHook, statesHook: ReactHook,
requestAdapter: xhrRequestAdapter() requestAdapter: xhrRequestAdapter()
}); });

View File

@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useBlocker } from 'react-router-dom'; import { useBlocker } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';

View File

@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useBlocker, useLocation } from 'react-router-dom'; import { useBlocker, useLocation } 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';

View File

@@ -107,7 +107,7 @@ const Dashboard = () => {
}, },
&:hover .td { &:hover .td {
background-color: #177ac9; background-color: #177ac9;
} },
`, `,
BaseCell: ` BaseCell: `
&:nth-of-type(2) { &:nth-of-type(2) {
@@ -185,18 +185,16 @@ const Dashboard = () => {
// if its a device (parent node) and has entities // if its a device (parent node) and has entities
if (di.nodes?.length) { if (di.nodes?.length) {
return ( return (
<> <span style={{ fontWeight: 'bold', fontSize: '14px' }}>
<span style="font-size: 14px"> <DeviceIcon type_id={di.t ?? 0} />
<DeviceIcon type_id={di.t ?? 0} /> &nbsp;&nbsp;{showType(di.n, di.t)}
&nbsp;&nbsp;{showType(di.n, di.t)}
</span>
<span style={{ color: 'lightblue' }}>&nbsp;({di.nodes?.length})</span> <span style={{ color: 'lightblue' }}>&nbsp;({di.nodes?.length})</span>
</> </span>
); );
} }
} }
if (di.dv) { if (di.dv) {
return <span style="color:lightgrey">{di.dv.id.slice(2)}</span>; return <span>{di.dv.id.slice(2)}</span>;
} }
}; };
@@ -250,10 +248,10 @@ const Dashboard = () => {
onChange={handleShowAll} onChange={handleShowAll}
> >
<ToggleButton value={true}> <ToggleButton value={true}>
<UnfoldMoreIcon sx={{ fontSize: 14 }} /> <UnfoldMoreIcon sx={{ fontSize: 18 }} />
</ToggleButton> </ToggleButton>
<ToggleButton value={false}> <ToggleButton value={false}>
<UnfoldLessIcon sx={{ fontSize: 14 }} /> <UnfoldLessIcon sx={{ fontSize: 18 }} />
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>
</Grid> </Grid>
@@ -304,9 +302,7 @@ const Dashboard = () => {
title={formatValue(LL, di.dv?.v, di.dv?.u)} title={formatValue(LL, di.dv?.v, di.dv?.u)}
arrow arrow
> >
<span style={{ color: 'lightgrey' }}> <span>{formatValue(LL, di.dv?.v, di.dv?.u)}</span>
{formatValue(LL, di.dv?.v, di.dv?.u)}
</span>
</Tooltip> </Tooltip>
</Cell> </Cell>

View File

@@ -6,7 +6,7 @@ import {
useState useState
} from 'react'; } from 'react';
import { IconContext } from 'react-icons'; import { IconContext } from 'react-icons';
import { useNavigate } from 'react-router-dom'; 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';
@@ -155,7 +155,6 @@ const Devices = () => {
} }
&.tr.tr-body.row-select.row-select-single-selected { &.tr.tr-body.row-select.row-select-single-selected {
background-color: #177ac9; background-color: #177ac9;
font-weight: normal;
} }
` `
}); });
@@ -169,11 +168,11 @@ const Devices = () => {
HeaderRow: ` HeaderRow: `
.th { .th {
padding: 8px; padding: 8px;
height: 36px;
`, `,
Row: ` Row: `
font-weight: bold;
&:hover .td { &:hover .td {
background-color: #177ac9; background-color: #177ac9;
` `
} }
]); ]);
@@ -216,7 +215,7 @@ const Devices = () => {
background-color: #303030; background-color: #303030;
}, },
&:hover .td { &:hover .td {
background-color: #177ac9; background-color: #177ac9;
} }
` `
} }
@@ -307,9 +306,9 @@ const Devices = () => {
const customize = () => { const customize = () => {
if (selectedDevice === 99) { if (selectedDevice === 99) {
navigate('/customentities'); void navigate('/customentities');
} else { } else {
navigate('/customizations', { state: selectedDevice }); void navigate('/customizations', { state: selectedDevice });
} }
}; };
@@ -523,7 +522,7 @@ const Devices = () => {
<IconContext.Provider <IconContext.Provider
value={{ value={{
color: 'lightblue', color: 'lightblue',
size: '18', size: '16',
style: { verticalAlign: 'middle' } style: { verticalAlign: 'middle' }
}} }}
> >
@@ -574,7 +573,9 @@ const Devices = () => {
const deviceValueDialogClose = () => { const deviceValueDialogClose = () => {
setDeviceValueDialogOpen(false); setDeviceValueDialogOpen(false);
void sendDeviceData(selectedDevice); if (selectedDevice !== undefined) {
void sendDeviceData(selectedDevice);
}
}; };
const renderDeviceData = () => { const renderDeviceData = () => {

View File

@@ -39,7 +39,7 @@ const Help = () => {
const [customSupportHTML, setCustomSupportHTML] = useState<string | null>(null); const [customSupportHTML, setCustomSupportHTML] = useState<string | null>(null);
const [notFound, setNotFound] = useState<boolean>(false); const [notFound, setNotFound] = useState<boolean>(false);
useRequest(() => callAction({ action: 'customSupport' })).onSuccess((event) => { useRequest(() => callAction({ action: 'getCustomSupport' })).onSuccess((event) => {
if (event && event.data && Object.keys(event.data).length !== 0) { if (event && event.data && Object.keys(event.data).length !== 0) {
const data = event.data.Support; const data = event.data.Support;
if (data.img_url) { if (data.img_url) {
@@ -78,44 +78,43 @@ const Help = () => {
return ( return (
<SectionContent> <SectionContent>
<Stack {customSupportHTML && (
padding={1} <Stack
mb={2} padding={1}
direction="row" mb={2}
divider={<Divider orientation="vertical" flexItem />} direction="row"
sx={{ divider={<Divider orientation="vertical" flexItem />}
borderRadius: 3,
border: '2px solid grey',
justifyContent: 'space-evenly',
alignItems: 'center'
}}
>
<Typography variant="subtitle1">
{customSupportHTML ? (
<div dangerouslySetInnerHTML={{ __html: customSupportHTML }} />
) : (
LL.HELP_INFORMATION_5()
)}
</Typography>
<Box
component="img"
referrerPolicy="no-referrer"
sx={{ sx={{
maxHeight: { xs: 100, md: 250 } borderRadius: 3,
border: '2px solid grey',
justifyContent: 'space-evenly',
alignItems: 'center'
}} }}
onError={() => setNotFound(true)} >
src={ <Typography variant="subtitle1">
notFound <div dangerouslySetInnerHTML={{ __html: customSupportHTML }} />
? '' </Typography>
: customSupportIMG || 'https://emsesp.org/_media/images/installer.jpeg' <Box
} component="img"
/> referrerPolicy="no-referrer"
</Stack> sx={{
maxHeight: { xs: 100, md: 250 }
}}
onError={() => setNotFound(true)}
src={
notFound
? ''
: customSupportIMG ||
'https://docs.emsesp.org/_media/images/installer.jpeg'
}
/>
</Stack>
)}
{me.admin && ( {me.admin && (
<List sx={{ borderRadius: 3, border: '2px solid grey' }}> <List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListItem> <ListItem>
<ListItemButton component="a" href="https://emsesp.org"> <ListItemButton component="a" href="https://docs.emsesp.org">
<ListItemAvatar> <ListItemAvatar>
<Avatar sx={{ bgcolor: '#72caf9' }}> <Avatar sx={{ bgcolor: '#72caf9' }}>
<MenuBookIcon /> <MenuBookIcon />

View File

@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useBlocker } from 'react-router-dom'; import { useBlocker } 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';

View File

@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useBlocker } from 'react-router-dom'; import { useBlocker } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';

View File

@@ -438,7 +438,8 @@ const Sensors = () => {
<Cell stiff>{a.g}</Cell> <Cell stiff>{a.g}</Cell>
<Cell>{a.n}</Cell> <Cell>{a.n}</Cell>
<Cell stiff>{AnalogTypeNames[a.t]} </Cell> <Cell stiff>{AnalogTypeNames[a.t]} </Cell>
{a.t === AnalogType.DIGITAL_OUT || a.t === AnalogType.DIGITAL_IN ? ( {(a.t === AnalogType.DIGITAL_OUT && a.g !== 25 && a.g !== 26) ||
a.t === AnalogType.DIGITAL_IN ? (
<Cell stiff>{a.v ? LL.ON() : LL.OFF()}</Cell> <Cell stiff>{a.v ? LL.ON() : LL.OFF()}</Cell>
) : ( ) : (
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell> <Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>

View File

@@ -181,7 +181,8 @@ export enum DeviceValueUOM {
K, K,
VOLTS, VOLTS,
MBAR, MBAR,
LH LH,
CTKWH
} }
export const DeviceValueUOM_s = [ export const DeviceValueUOM_s = [
@@ -210,7 +211,8 @@ export const DeviceValueUOM_s = [
'K', 'K',
'V', 'V',
'mbar', 'mbar',
'l/h' 'l/h',
'ct/kWh'
]; ];
export enum AnalogType { export enum AnalogType {

View File

@@ -383,8 +383,8 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
{ type: 'number', min: 0, max: 255, message: 'Must be between 0 and 255' } { type: 'number', min: 0, max: 255, message: 'Must be between 0 and 255' }
], ],
factor: [ factor: [
{ required: true, message: 'Bytes is required' }, { required: true, message: 'is required' },
{ type: 'number', min: 1, max: 255, message: 'Must be between 1 and 255' } { type: 'number', message: 'Must be a number' }
] ]
}); });

View File

@@ -46,7 +46,7 @@ const APSettings = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF(LL.ACCESS_POINT(0))); useLayoutTitle(LL.ACCESS_POINT(0));
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>(); const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();

View File

@@ -121,7 +121,7 @@ const ApplicationSettings = () => {
}); });
}; };
useLayoutTitle(LL.SETTINGS_OF(LL.APPLICATION())); useLayoutTitle(LL.APPLICATION());
const SecondsInputProps = { const SecondsInputProps = {
endAdornment: <InputAdornment position="end">{LL.SECONDS()}</InputAdornment> endAdornment: <InputAdornment position="end">{LL.SECONDS()}</InputAdornment>

View File

@@ -48,7 +48,7 @@ const MqttSettings = () => {
}); });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF('MQTT')); useLayoutTitle('MQTT');
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>(); const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();

View File

@@ -44,7 +44,7 @@ const NTPSettings = () => {
}); });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF('NTP')); useLayoutTitle('NTP');
const updateFormValue = updateValueDirty( const updateFormValue = updateValueDirty(
origData, origData,
@@ -71,12 +71,12 @@ const NTPSettings = () => {
}; };
const changeTimeZone = (event: React.ChangeEvent<HTMLInputElement>) => { const changeTimeZone = (event: React.ChangeEvent<HTMLInputElement>) => {
updateFormValue(event);
void updateState(readNTPSettings(), (settings: NTPSettingsType) => ({ void updateState(readNTPSettings(), (settings: NTPSettingsType) => ({
...settings, ...settings,
tz_label: event.target.value, tz_label: event.target.value,
tz_format: TIME_ZONES[event.target.value] tz_format: TIME_ZONES[event.target.value]
})); }));
updateFormValue(event);
}; };
return ( return (

View File

@@ -86,8 +86,8 @@ const Settings = () => {
<ListMenuItem <ListMenuItem
icon={BuildIcon} icon={BuildIcon}
bgcolor="#72caf9" bgcolor="#72caf9"
label={LL.EMS_ESP_VER()} label="EMS-ESP Firmware"
text={data.emsesp_version} text={'v' + data.emsesp_version}
to="version" to="version"
/> />

View File

@@ -1,7 +1,9 @@
import { useState } from 'react'; import { useEffect, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import CheckIcon from '@mui/icons-material/Done';
import DownloadIcon from '@mui/icons-material/GetApp';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { import {
@@ -11,7 +13,6 @@ import {
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogTitle, DialogTitle,
Divider,
Link, Link,
Typography Typography
} from '@mui/material'; } from '@mui/material';
@@ -29,46 +30,12 @@ import { useI18nContext } from 'i18n/i18n-react';
const Version = () => { const Version = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [restarting, setRestarting] = useState<boolean>(false); const [restarting, setRestarting] = useState<boolean>(false);
const [openDialog, setOpenDialog] = useState<boolean>(false); const [openInstallDialog, setOpenInstallDialog] = useState<boolean>(false);
const [useDev, setUseDev] = useState<boolean>(false); const [usingDevVersion, setUsingDevVersion] = useState<boolean>(false);
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(false); const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(false);
const [internetLive, setInternetLive] = useState<boolean>(false);
const { send: sendCheckUpgrade } = useRequest( const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
(version: string) => callAction({ action: 'checkUpgrade', param: version }),
{
immediate: false
}
).onSuccess((event) => {
const data = event.data as { emsesp_version: string; upgradeable: boolean };
setUpgradeAvailable(data.upgradeable);
});
const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
const { send: sendUploadURL } = useRequest(
(url: string) => callAction({ action: 'uploadURL', param: url }),
{
immediate: false
}
);
// called immediately to get the latest version, on page load
const { data: latestVersion } = useRequest(getStableVersion, {
// uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/v3.6.5/EMS-ESP-3_6_5-ESP32-16MB+.bin
// immediate: false,
// initialData: '3.6.5'
});
// called immediately to get the latest version, on page load, then check for upgrade (works for both dev and stable)
const { data: latestDevVersion } = useRequest(getDevVersion, {
// uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/latest/EMS-ESP-3_7_0-dev_31-ESP32-16MB+.bin
// immediate: false,
// initialData: '3.7.0-dev.32'
}).onSuccess((event) => {
void sendCheckUpgrade(event.data);
});
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/'; const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
const STABLE_RELNOTES_URL = const STABLE_RELNOTES_URL =
@@ -78,17 +45,60 @@ const Version = () => {
const DEV_RELNOTES_URL = const DEV_RELNOTES_URL =
'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md'; 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
const getBinURL = (useDevVersion: boolean) => { const { send: sendCheckUpgrade } = useRequest(
(versions: string) => callAction({ action: 'checkUpgrade', param: versions }),
{
immediate: false
}
).onSuccess((event) => {
const data = event.data as { emsesp_version: string; upgradeable: boolean };
setUpgradeAvailable(data.upgradeable);
});
const {
data: data,
send: loadData,
error
} = useRequest(SystemApi.readSystemStatus).onSuccess((event) => {
// older version of EMS-ESP didn't have the psram set, so we can't do an OTA upgrade
setDownloadOnly(event.data.psram === undefined);
setUsingDevVersion(event.data.emsesp_version.includes('dev'));
});
const { send: sendUploadURL } = useRequest(
(url: string) => callAction({ action: 'uploadURL', param: url }),
{
immediate: false
}
);
// called immediately to get the latest versions on page load
const { data: latestVersion } = useRequest(getStableVersion);
const { data: latestDevVersion } = useRequest(getDevVersion);
useEffect(() => {
if (latestVersion && latestDevVersion) {
sendCheckUpgrade(latestDevVersion + ',' + latestVersion)
.catch((error: Error) => {
toast.error('Failed to check for upgrades: ' + error.message);
})
.finally(() => {
setInternetLive(true);
});
}
}, [latestVersion, latestDevVersion]);
const getBinURL = () => {
if (!latestVersion || !latestDevVersion) { if (!latestVersion || !latestDevVersion) {
return ''; return '';
} }
const filename = const filename =
'EMS-ESP-' + 'EMS-ESP-' +
(useDevVersion ? latestDevVersion : latestVersion).replaceAll('.', '_') + (usingDevVersion ? latestDevVersion : latestVersion).replaceAll('.', '_') +
'-' + '-' +
getPlatform() + getPlatform() +
'.bin'; '.bin';
return useDevVersion return usingDevVersion
? DEV_URL + filename ? DEV_URL + filename
: STABLE_URL + 'v' + latestVersion + '/' + filename; : STABLE_URL + 'v' + latestVersion + '/' + filename;
}; };
@@ -107,97 +117,131 @@ const Version = () => {
setRestarting(true); setRestarting(true);
}; };
useLayoutTitle(LL.EMS_ESP_VER()); useLayoutTitle('EMS-ESP Firmware');
const internet_live = const renderInstallDialog = () => (
latestDevVersion !== undefined && latestVersion !== undefined; <Dialog
sx={dialogStyle}
open={openInstallDialog}
onClose={() => closeInstallDialog()}
>
<DialogTitle>
{LL.INSTALL() +
' ' +
(usingDevVersion ? LL.DEVELOPMENT() : LL.STABLE()) +
' Firmware'}
</DialogTitle>
<DialogContent dividers>
<Typography mb={2}>
{LL.INSTALL_VERSION(usingDevVersion ? latestDevVersion : latestVersion)}
</Typography>
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => closeInstallDialog()}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<DownloadIcon />}
variant="outlined"
onClick={() => closeInstallDialog()}
color="primary"
>
<Link underline="none" target="_blank" href={getBinURL()} color="primary">
{LL.DOWNLOAD(1)}
</Link>
</Button>
<Button
startIcon={<WarningIcon color="warning" />}
variant="outlined"
onClick={() => installFirmwareURL(getBinURL())}
color="primary"
>
{LL.INSTALL()}
</Button>
</DialogActions>
</Dialog>
);
const renderUploadDialog = () => { const showFirmwareDialog = (useDevVersion?: boolean) => {
if (!internet_live) { setUsingDevVersion(useDevVersion || usingDevVersion);
return null; setOpenInstallDialog(true);
};
const closeInstallDialog = () => {
setOpenInstallDialog(false);
setUsingDevVersion(data.emsesp_version.includes('dev'));
};
const switchToDev = () => {
setUsingDevVersion(true);
setUpgradeAvailable(true);
};
const showButtons = () => {
if (!upgradeAvailable) {
return;
}
if (downloadOnly) {
return (
<Button
startIcon={<DownloadIcon />}
variant="outlined"
onClick={() => setOpenInstallDialog(false)}
color="warning"
size="small"
sx={{ ml: 2 }}
>
<Link underline="none" target="_blank" href={getBinURL()} color="warning">
{LL.DOWNLOAD(1)}
</Link>
</Button>
);
} }
return ( return (
<Dialog <Button
sx={dialogStyle} sx={{ ml: 2 }}
open={openDialog} variant="outlined"
onClose={() => setOpenDialog(false)} color="warning"
size="small"
onClick={() => showFirmwareDialog()}
> >
<DialogTitle> {LL.UPGRADE()}&hellip;
{LL.INSTALL('') + </Button>
' ' +
(useDev ? LL.DEVELOPMENT() : LL.STABLE()) +
' Firmware'}
</DialogTitle>
<DialogContent dividers>
<Typography mb={2}>
{LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)}
</Typography>
<Link
target="_blank"
href={useDev ? DEV_RELNOTES_URL : STABLE_RELNOTES_URL}
color="primary"
>
changelog
</Link>
&nbsp;|&nbsp;
<Link target="_blank" href={getBinURL(useDev)} color="primary">
{LL.DOWNLOAD(1)}
</Link>
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => setOpenDialog(false)}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<WarningIcon color="warning" />}
variant="outlined"
onClick={() => installFirmwareURL(getBinURL(useDev))}
color="primary"
>
{LL.INSTALL('')}
</Button>
</DialogActions>
</Dialog>
); );
}; };
// useDevVersion = true to force using the dev version
const showFirmwareDialog = (useDevVersion: boolean) => {
if (useDevVersion || data.emsesp_version.includes('dev')) {
setUseDev(true);
}
setOpenDialog(true);
};
const content = () => { const content = () => {
if (!data) { if (!data) {
return <FormLoader onRetry={loadData} errorMessage={error?.message} />; return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
} }
const isDev = data.emsesp_version.includes('dev');
return ( return (
<> <>
<Box p={2} border="1px solid grey" borderRadius={2}> <Box p={2} border="1px solid grey" borderRadius={2}>
<Grid container spacing={3}> <Typography sx={{ pb: 2 }} variant="h6" color="primary">
Firmware Version
</Typography>
<Grid container spacing={4}>
<Grid mb={1}> <Grid mb={1}>
<Typography mb={1} fontWeight={'fontWeightBold'}> <Typography mb={1} color="secondary">
{LL.VERSION()} {LL.VERSION()}
</Typography> </Typography>
<Typography mb={1} fontWeight={'fontWeightBold'}> <Typography mb={1} color="secondary">
Platform Platform
</Typography> </Typography>
<Typography mb={1} fontWeight={'fontWeightBold'}> <Typography mb={1} color="secondary">
Release Release Type
</Typography> </Typography>
</Grid> </Grid>
<Grid> <Grid mb={1}>
<Typography mb={1}> <Typography mb={1}>
{data.emsesp_version} {data.emsesp_version}
{data.build_flags && ( {data.build_flags && (
@@ -207,63 +251,86 @@ const Version = () => {
)} )}
</Typography> </Typography>
<Typography mb={1}>{getPlatform()}</Typography> <Typography mb={1}>{getPlatform()}</Typography>
<Typography> <Typography mb={1}>
{isDev ? LL.DEVELOPMENT() : LL.STABLE()}&nbsp; {data.emsesp_version.includes('dev')
<Link ? LL.DEVELOPMENT()
target="_blank" : LL.STABLE()}
href={useDev ? DEV_RELNOTES_URL : STABLE_RELNOTES_URL}
color="primary"
>
(changelog)
</Link>
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
<Divider /> <Typography sx={{ pb: 2 }} variant="h6" color="primary">
{LL.AVAILABLE_VERSION()}
{!isDev && (
<Button
sx={{ mt: 2 }}
variant="outlined"
color="primary"
size="small"
onClick={() => showFirmwareDialog(true)}
>
{LL.SWITCH_DEV()}
</Button>
)}
<Typography mt={2} color="warning">
<InfoOutlinedIcon color="warning" sx={{ verticalAlign: 'middle' }} />
&nbsp;&nbsp;
{upgradeAvailable ? LL.UPGRADE_AVAILABLE() : LL.LATEST_VERSION()}
{upgradeAvailable &&
internet_live &&
(data.psram ? (
<Button
sx={{ ml: 2, textTransform: 'none' }}
variant="outlined"
color="primary"
size="small"
onClick={() => showFirmwareDialog(false)}
>
{isDev
? LL.INSTALL('v' + latestDevVersion)
: LL.INSTALL('v' + latestVersion)}
</Button>
) : (
<>
&nbsp;&nbsp;
<Link target="_blank" href={getBinURL(isDev)} color="primary">
{LL.DOWNLOAD(1)}&nbsp;v
{isDev ? latestDevVersion : latestVersion}
</Link>
</>
))}
</Typography> </Typography>
{renderUploadDialog()} {internetLive ? (
<>
<Grid container spacing={4}>
<Grid mb={1}>
<Typography mb={1} color="secondary">
{LL.STABLE()}
</Typography>
<Typography mb={1} color="secondary">
{LL.DEVELOPMENT()}
</Typography>
</Grid>
<Grid mb={1}>
<Typography mb={1}>
{latestVersion}&nbsp;&nbsp;
<Link target="_blank" href={STABLE_RELNOTES_URL} color="primary">
(changelog)
</Link>
{!usingDevVersion && showButtons()}
</Typography>
<Typography mb={1}>
{latestDevVersion}&nbsp;&nbsp;
<Link target="_blank" href={DEV_RELNOTES_URL} color="primary">
(changelog)
</Link>
{usingDevVersion && showButtons()}
</Typography>
</Grid>
</Grid>
{upgradeAvailable ? (
<Typography color="warning">
<InfoOutlinedIcon
color="warning"
sx={{ verticalAlign: 'middle', mr: 2 }}
/>
{LL.UPGRADE_AVAILABLE()}
</Typography>
) : (
<Typography color="success">
<CheckIcon
color="success"
sx={{ verticalAlign: 'middle', mr: 2 }}
/>
{LL.LATEST_VERSION()}
</Typography>
)}
{!data.emsesp_version.includes('dev') && !usingDevVersion && (
<Typography variant="caption">
<Button
sx={{ mt: 2 }}
variant="outlined"
color="primary"
size="small"
onClick={() => switchToDev()}
>
{LL.SWITCH_DEV()}
</Button>
</Typography>
)}
</>
) : (
<Typography mb={1} color="warning">
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
device cannot access internet
</Typography>
)}
{renderInstallDialog()}
</Box> </Box>
</> </>
); );

View File

@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { Navigate, Route, Routes, useNavigate } from 'react-router-dom'; import { Navigate, Route, Routes, useNavigate } from 'react-router';
import { Tab } from '@mui/material'; import { Tab } from '@mui/material';
@@ -13,7 +13,7 @@ import WiFiNetworkScanner from './WiFiNetworkScanner';
const Network = () => { const Network = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF(LL.NETWORK(0))); useLayoutTitle(LL.NETWORK(0));
const { routerTab } = useRouterTab(); const { routerTab } = useRouterTab();
@@ -24,7 +24,7 @@ const Network = () => {
const selectNetwork = useCallback( const selectNetwork = useCallback(
(network: WiFiNetwork) => { (network: WiFiNetwork) => {
setSelectedNetwork(network); setSelectedNetwork(network);
navigate('settings'); void navigate('/settings');
}, },
[navigate] [navigate]
); );

View File

@@ -1,10 +1,10 @@
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import { useBlocker } from 'react-router-dom'; import { useBlocker } from 'react-router';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import CheckIcon from '@mui/icons-material/Done';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import PersonAddIcon from '@mui/icons-material/PersonAdd'; import PersonAddIcon from '@mui/icons-material/PersonAdd';
import VpnKeyIcon from '@mui/icons-material/VpnKey'; import VpnKeyIcon from '@mui/icons-material/VpnKey';

View File

@@ -1,4 +1,4 @@
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router';
import { Tab } from '@mui/material'; import { Tab } from '@mui/material';
@@ -10,7 +10,7 @@ import SecuritySettings from './SecuritySettings';
const Security = () => { const Security = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF(LL.SECURITY(0))); useLayoutTitle(LL.SECURITY(0));
const { routerTab } = useRouterTab(); const { routerTab } = useRouterTab();

View File

@@ -41,7 +41,7 @@ const APStatus = () => {
} = useAutoRequest(APApi.readAPStatus, { pollingTime: 3000 }); } = useAutoRequest(APApi.readAPStatus, { pollingTime: 3000 });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF(LL.ACCESS_POINT(0))); useLayoutTitle(LL.ACCESS_POINT(0));
const theme = useTheme(); const theme = useTheme();

View File

@@ -30,7 +30,7 @@ function formatNumber(num: number) {
const HardwareStatus = () => { const HardwareStatus = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF(LL.HARDWARE())); useLayoutTitle(LL.HARDWARE());
const { const {
data, data,

View File

@@ -61,7 +61,7 @@ const MqttStatus = () => {
} = useAutoRequest(MqttApi.readMqttStatus, { pollingTime: 3000 }); } = useAutoRequest(MqttApi.readMqttStatus, { pollingTime: 3000 });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF('MQTT')); useLayoutTitle('MQTT');
const theme = useTheme(); const theme = useTheme();
@@ -70,9 +70,9 @@ const MqttStatus = () => {
return LL.NOT_ENABLED(); return LL.NOT_ENABLED();
} }
if (connected) { if (connected) {
return LL.CONNECTED(0) + (connect_count > 1 ? ' (' + connect_count + ')' : ''); return LL.CONNECTED(0) + ' (' + connect_count + ')';
} }
return LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : ''); return LL.DISCONNECTED() + ' (' + connect_count + ')';
}; };
const disconnectReason = ({ disconnect_reason }: MqttStatusType) => { const disconnectReason = ({ disconnect_reason }: MqttStatusType) => {

View File

@@ -47,7 +47,7 @@ const NTPStatus = () => {
const [processing, setProcessing] = useState<boolean>(false); const [processing, setProcessing] = useState<boolean>(false);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF('NTP')); useLayoutTitle('NTP');
const { send: updateTime } = useRequest( const { send: updateTime } = useRequest(
(local_time: Time) => NTPApi.updateTime(local_time), (local_time: Time) => NTPApi.updateTime(local_time),

View File

@@ -88,12 +88,14 @@ const NetworkStatus = () => {
} = useAutoRequest(NetworkApi.readNetworkStatus, { pollingTime: 3000 }); } = useAutoRequest(NetworkApi.readNetworkStatus, { pollingTime: 3000 });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF(LL.NETWORK(1))); useLayoutTitle(LL.NETWORK(1));
const theme = useTheme(); const theme = useTheme();
const networkStatus = ({ status }: NetworkStatusType) => { const networkStatus = ({ status }: NetworkStatusType) => {
switch (status) { switch (status) {
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
return LL.CONNECTED(0) + ' (Ethernet)';
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
return LL.INACTIVE(1); return LL.INACTIVE(1);
case NetworkConnectionStatus.WIFI_STATUS_IDLE: case NetworkConnectionStatus.WIFI_STATUS_IDLE:
@@ -101,13 +103,13 @@ const NetworkStatus = () => {
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
return 'No SSID Available'; return 'No SSID Available';
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
return LL.CONNECTED(0) + ' (WiFi)'; return LL.CONNECTED(0) + ' (WiFi) (' + data.reconnect_count + ')';
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
return LL.CONNECTED(0) + ' (Ethernet)';
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
return LL.CONNECTED(1) + ' ' + LL.FAILED(0); return (
LL.CONNECTED(1) + ' ' + LL.FAILED(0) + ' (' + data.reconnect_count + ')'
);
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
return LL.CONNECTED(1) + ' ' + LL.LOST(); return LL.CONNECTED(1) + ' ' + LL.LOST() + ' (' + data.reconnect_count + ')';
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
return LL.DISCONNECTED(); return LL.DISCONNECTED();
default: default:

View File

@@ -261,16 +261,6 @@ const SystemLog = () => {
> >
{LL.EXPORT()} {LL.EXPORT()}
</Button> </Button>
{dirtyFlags && dirtyFlags.length !== 0 && (
<Button
startIcon={<WarningIcon color="warning" />}
variant="contained"
color="info"
onClick={saveSettings}
>
{LL.APPLY_CHANGES(dirtyFlags.length)}
</Button>
)}
</Grid> </Grid>
{readOpen ? ( {readOpen ? (
@@ -315,6 +305,19 @@ const SystemLog = () => {
)} )}
</> </>
)} )}
{dirtyFlags && dirtyFlags.length !== 0 && (
<Grid>
<Button
startIcon={<WarningIcon color="warning" />}
variant="contained"
color="info"
onClick={saveSettings}
>
{LL.APPLY_CHANGES(dirtyFlags.length)}
</Button>
</Grid>
)}
</Grid> </Grid>
<Box <Box

View File

@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router';
import { Box, Toolbar } from '@mui/material'; import { Box, Toolbar } from '@mui/material';

View File

@@ -1,9 +1,11 @@
import { useLocation, useNavigate } from 'react-router-dom'; import { Link, useLocation, useNavigate } from 'react-router';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import MenuIcon from '@mui/icons-material/Menu'; import MenuIcon from '@mui/icons-material/Menu';
import { AppBar, IconButton, Toolbar, Typography } from '@mui/material'; import { AppBar, IconButton, Toolbar, Typography } from '@mui/material';
import { useI18nContext } from 'i18n/i18n-react';
export const DRAWER_WIDTH = 210; export const DRAWER_WIDTH = 210;
interface LayoutAppBarProps { interface LayoutAppBarProps {
@@ -12,12 +14,12 @@ interface LayoutAppBarProps {
} }
const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => { const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => {
const { LL } = useI18nContext();
const navigate = useNavigate();
const pathnames = useLocation() const pathnames = useLocation()
.pathname.split('/') .pathname.split('/')
.filter((x) => x); .filter((x) => x);
const show_back = pathnames.length > 1;
const navigate = useNavigate();
return ( return (
<AppBar <AppBar
@@ -39,20 +41,30 @@ const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => {
<MenuIcon /> <MenuIcon />
</IconButton> </IconButton>
{show_back && ( {pathnames.length > 1 && (
<IconButton <>
sx={{ mr: 1 }} <IconButton
color="inherit" sx={{ mr: 1, fontSize: 20, verticalAlign: 'middle' }}
edge="start" color="primary"
onClick={() => navigate(pathnames[0])} edge="start"
> onClick={() => navigate('/' + pathnames[0])}
<ArrowBackIcon /> >
</IconButton> <ArrowBackIcon />
</IconButton>
<Link
to={'/' + pathnames[0]}
style={{ textDecoration: 'none', color: 'white' }}
>
<Typography variant="h6">
{pathnames[0] === 'status' ? LL.STATUS_OF('') : LL.SETTINGS(0)}
<span style={{ color: '#90caf9' }}>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
</Typography>
</Link>
</>
)} )}
<Typography variant="h6" noWrap component="div"> <Typography variant="h6">{title}</Typography>
{title}
</Typography>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
); );

View File

@@ -1,4 +1,4 @@
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router';
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
import type { SvgIconProps } from '@mui/material'; import type { SvgIconProps } from '@mui/material';

View File

@@ -1,4 +1,4 @@
import { Link } from 'react-router-dom'; import { Link } from 'react-router';
import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import { import {

View File

@@ -1,4 +1,4 @@
import type { Blocker } from 'react-router-dom'; import type { Blocker } from 'react-router';
import { import {
Button, Button,

View File

@@ -1,6 +1,6 @@
import { useContext } from 'react'; import { useContext } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { Navigate } from 'react-router-dom'; import { Navigate } from 'react-router';
import { AuthenticatedContext } from 'contexts/authentication'; import { AuthenticatedContext } from 'contexts/authentication';
import type { RequiredChildrenProps } from 'utils'; import type { RequiredChildrenProps } from 'utils';

View File

@@ -1,6 +1,6 @@
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { Navigate, useLocation } from 'react-router-dom'; import { Navigate, useLocation } from 'react-router';
import { storeLoginRedirect } from 'components/routing/authentication'; import { storeLoginRedirect } from 'components/routing/authentication';
import type { AuthenticatedContextValue } from 'contexts/authentication/context'; import type { AuthenticatedContextValue } from 'contexts/authentication/context';

View File

@@ -1,6 +1,6 @@
import { useContext } from 'react'; import { useContext } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { Navigate } from 'react-router-dom'; import { Navigate } from 'react-router';
import { fetchLoginRedirect } from 'components/routing/authentication'; import { fetchLoginRedirect } from 'components/routing/authentication';
import { AuthenticationContext } from 'contexts/authentication'; import { AuthenticationContext } from 'contexts/authentication';

View File

@@ -1,5 +1,5 @@
import type { FC } from 'react'; import type { FC } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router';
import { Tabs, useMediaQuery, useTheme } from '@mui/material'; import { Tabs, useMediaQuery, useTheme } from '@mui/material';
@@ -16,7 +16,7 @@ const RouterTabs: FC<RouterTabsProps> = ({ value, children }) => {
const smallDown = useMediaQuery(theme.breakpoints.down('sm')); const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
const handleTabChange = (_event: unknown, path: string) => { const handleTabChange = (_event: unknown, path: string) => {
navigate(path); void navigate(path);
}; };
return ( return (

View File

@@ -1,4 +1,4 @@
import type { Path } from 'react-router-dom'; import type { Path } from 'react-router';
import type * as H from 'history'; import type * as H from 'history';
import { jwtDecode } from 'jwt-decode'; import { jwtDecode } from 'jwt-decode';

View File

@@ -1,4 +1,4 @@
import { useMatch, useResolvedPath } from 'react-router-dom'; import { useMatch, useResolvedPath } from 'react-router';
export const useRouterTab = () => { export const useRouterTab = () => {
const routerTabPathMatch = useMatch(useResolvedPath(':tab').pathname); const routerTabPathMatch = useMatch(useResolvedPath(':tab').pathname);

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { redirect } from 'react-router-dom'; import { redirect } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { ACCESS_TOKEN } from 'api/endpoints'; import { ACCESS_TOKEN } from 'api/endpoints';

View File

@@ -116,12 +116,12 @@ const cz: Translation = {
UNDERCLOCK_CPU: 'Snížit takt CPU', UNDERCLOCK_CPU: 'Snížit takt CPU',
REMOTE_TIMEOUT: 'Časový limit vzdáleného připojení', REMOTE_TIMEOUT: 'Časový limit vzdáleného připojení',
REMOTE_TIMEOUT_EN: 'Zakázat vzdálený přístup při chybějící teplotě v místnosti', REMOTE_TIMEOUT_EN: 'Zakázat vzdálený přístup při chybějící teplotě v místnosti',
HEATINGOFF: 'Spustit kotel s vynuceným vypnutým topením', HEATINGOFF: 'Vynutit vypnuté topení při spuštění kotle',
MIN_DURATION: 'Čekací doba', MIN_DURATION: 'Čekací doba',
ENABLE_SHOWER_TIMER: 'Povolit časovač sprchy', ENABLE_SHOWER_TIMER: 'Povolit časovač sprchy',
ENABLE_SHOWER_ALERT: 'Povolit upozornění na sprchu', ENABLE_SHOWER_ALERT: 'Povolit upozornění na sprchu',
TRIGGER_TIME: 'Čas spuštění', TRIGGER_TIME: 'Čas spuštění',
COLD_SHOT_DURATION: 'Délka studeného výstřiku', COLD_SHOT_DURATION: 'Délka studeného výtrysku',
FORMATTING_OPTIONS: 'Možnosti formátování', FORMATTING_OPTIONS: 'Možnosti formátování',
BOOLEAN_FORMAT_DASHBOARD: 'Formát booleovské hodnoty na webu', BOOLEAN_FORMAT_DASHBOARD: 'Formát booleovské hodnoty na webu',
BOOLEAN_FORMAT_API: 'Formát booleovské hodnoty v API/MQTT', BOOLEAN_FORMAT_API: 'Formát booleovské hodnoty v API/MQTT',
@@ -137,17 +137,17 @@ const cz: Translation = {
MINUTES: 'minuty', MINUTES: 'minuty',
HOURS: 'hodiny', HOURS: 'hodiny',
RESTART: 'Restart', RESTART: 'Restart',
RESTART_TEXT: 'EMS-ESP musí být restartován, aby se změny systému projevily', RESTART_TEXT: 'Pro projevení změn musí být zařízení EMS-ESP restartováno',
RESTART_CONFIRM: 'Opravdu chcete restartovat EMS-ESP?', RESTART_CONFIRM: 'Opravdu chcete restartovat zařízení EMS-ESP?',
COMMAND: 'Příkaz', COMMAND: 'Příkaz',
CUSTOMIZATIONS_RESTART: 'Všechna přizpůsobení byla odstraněna. Restartování...', CUSTOMIZATIONS_RESTART: 'Všechna přizpůsobení byla odstraněna. Restartování...',
CUSTOMIZATIONS_FULL: 'Vybrané entity překročily limit. Uložte je po částech', CUSTOMIZATIONS_FULL: 'Vybrané entity překročily limit. Ukládejte je postupně',
CUSTOMIZATIONS_SAVED: 'Přizpůsobení uloženo', CUSTOMIZATIONS_SAVED: 'Přizpůsobení uloženo',
CUSTOMIZATIONS_HELP_1: 'Vyberte zařízení a přizpůsobte možnosti entit nebo klikněte pro přejmenování', CUSTOMIZATIONS_HELP_1: 'Vyberte zařízení a přizpůsobte možnosti entit nebo klikněte pro přejmenování',
CUSTOMIZATIONS_HELP_2: 'označit jako oblíbené', CUSTOMIZATIONS_HELP_2: 'označit jako oblíbené',
CUSTOMIZATIONS_HELP_3: 'zakázat akci zápisu', CUSTOMIZATIONS_HELP_3: 'zakázat akci zápisu',
CUSTOMIZATIONS_HELP_4: 'vyloučit z MQTT a API', CUSTOMIZATIONS_HELP_4: 'vyloučit z MQTT a API',
CUSTOMIZATIONS_HELP_5: 'skrýt z Zařízení', CUSTOMIZATIONS_HELP_5: 'skrýt ze Zařízení',
CUSTOMIZATIONS_HELP_6: 'odstranit z paměti', CUSTOMIZATIONS_HELP_6: 'odstranit z paměti',
SELECT_DEVICE: 'Vyberte zařízení', SELECT_DEVICE: 'Vyberte zařízení',
SET_ALL: 'nastavit vše', SET_ALL: 'nastavit vše',
@@ -156,13 +156,12 @@ const cz: Translation = {
CUSTOMIZATIONS_RESET: 'Opravdu chcete odstranit všechna přizpůsobení včetně vlastních nastavení teplotních a analogových senzorů?', CUSTOMIZATIONS_RESET: 'Opravdu chcete odstranit všechna přizpůsobení včetně vlastních nastavení teplotních a analogových senzorů?',
SUPPORT_INFORMATION: 'Podpora', SUPPORT_INFORMATION: 'Podpora',
HELP_INFORMATION_1: 'Navštivte online wiki pro pokyny, jak konfigurovat EMS-ESP', HELP_INFORMATION_1: 'Navštivte online wiki pro pokyny, jak konfigurovat EMS-ESP',
HELP_INFORMATION_2: 'Pro živý chat se komunitou se připojte k našemu serveru Discord', HELP_INFORMATION_2: 'Pro živý chat s komunitou se připojte k našemu serveru Discord',
HELP_INFORMATION_3: 'Chcete-li požádat o funkci nebo nahlásit chybu', HELP_INFORMATION_3: 'Požádejte o funkci nebo nahlášte chybu',
HELP_INFORMATION_4: 'Stáhněte a připojte informace o podpoře pro rychlejší odezvu při hlášení problému', HELP_INFORMATION_4: 'Stáhněte a připojte informace podpoře pro rychlejší odezvu při hlášení problému',
HELP_INFORMATION_5: 'Pro pomoc a dotazy kontaktujte svého instalatéra',
UPLOAD: 'Nahrát', UPLOAD: 'Nahrát',
DOWNLOAD: '{{S|s|s}}táhnout', DOWNLOAD: '{{S|s|s}}táhnout',
INSTALL: 'Instalovat {0}', INSTALL: 'Instalovat',
ABORTED: 'přerušeno', ABORTED: 'přerušeno',
FAILED: 'neúspěšné', FAILED: 'neúspěšné',
SUCCESSFUL: 'úspěšné', SUCCESSFUL: 'úspěšné',
@@ -174,17 +173,17 @@ const cz: Translation = {
USE: 'Použít', USE: 'Použít',
FACTORY_RESET: 'Obnovení továrního nastavení', FACTORY_RESET: 'Obnovení továrního nastavení',
SYSTEM_FACTORY_TEXT: 'Zařízení bylo obnoveno do továrního nastavení a nyní se restartuje', SYSTEM_FACTORY_TEXT: 'Zařízení bylo obnoveno do továrního nastavení a nyní se restartuje',
SYSTEM_FACTORY_TEXT_DIALOG: 'Opravdu chcete resetovat EMS-ESP do továrního nastavení?', SYSTEM_FACTORY_TEXT_DIALOG: 'Opravdu chcete resetovat zařízení EMS-ESP do továrního nastavení?',
AVAILABLE_VERSION: 'Nejnovější dostupné verze',
STABLE: 'Stabilní', STABLE: 'Stabilní',
DEVELOPMENT: 'Vývojová verze', DEVELOPMENT: 'Vývojová verze',
EMS_ESP_VER: 'Verze firmwaru',
UPTIME: 'Doba provozu systému', UPTIME: 'Doba provozu systému',
FREE_MEMORY: 'Volná paměť', FREE_MEMORY: 'Volná paměť',
PSRAM: 'PSRAM (Velikost / Volná)', PSRAM: 'PSRAM (Velikost / Volná)',
FLASH: 'Flash čip (Velikost, Rychlost)', FLASH: 'Flash čip (Velikost, Rychlost)',
APPSIZE: 'Aplikace (Partition: Použito / Volné)', APPSIZE: 'Aplikace (Partition: Použito / Volné)',
FILESYSTEM: 'Souborový systém (Použito / Volné)', FILESYSTEM: 'Souborový systém (Použito / Volné)',
BUFFER_SIZE: 'Maximální velikost bufferu', 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',
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)',
@@ -193,7 +192,7 @@ const cz: Translation = {
TIME_SET: 'Čas nastaven', TIME_SET: 'Čas nastaven',
MANAGE_USERS: 'Spravovat uživatele', MANAGE_USERS: 'Spravovat uživatele',
IS_ADMIN: 'je Admin', IS_ADMIN: 'je Admin',
USER_WARNING: 'Musí být nakonfigurován alespoň jeden uživatel s oprávněním admin', USER_WARNING: 'Musí být nastaven alespoň jeden uživatel s oprávněním admin',
ADD: 'Přidat', ADD: 'Přidat',
ACCESS_TOKEN_FOR: 'Přístupový token pro', ACCESS_TOKEN_FOR: 'Přístupový token pro',
ACCESS_TOKEN_TEXT: 'Níže uvedený token se používá s REST API voláními, která vyžadují autorizaci. Lze jej předat buď jako Bearer token v hlavičce Authorization, nebo v parametru URL access_token.', ACCESS_TOKEN_TEXT: 'Níže uvedený token se používá s REST API voláními, která vyžadují autorizaci. Lze jej předat buď jako Bearer token v hlavičce Authorization, nebo v parametru URL access_token.',
@@ -220,10 +219,10 @@ const cz: Translation = {
MQTT_PUBLISH_TEXT_4: 'Prefix pro Discovery témata', MQTT_PUBLISH_TEXT_4: 'Prefix pro Discovery témata',
MQTT_PUBLISH_TEXT_5: 'Typ Discovery', MQTT_PUBLISH_TEXT_5: 'Typ Discovery',
MQTT_PUBLISH_INTERVALS: 'Intervaly publikování', MQTT_PUBLISH_INTERVALS: 'Intervaly publikování',
MQTT_INT_BOILER: 'Kotly a tepelná čerpadla', MQTT_INT_BOILER: 'Kotle a tepelná čerpadla',
MQTT_INT_THERMOSTATS: 'Termostaty', MQTT_INT_THERMOSTATS: 'Termostaty',
MQTT_INT_SOLAR: 'Solární moduly', MQTT_INT_SOLAR: 'Solární moduly',
MQTT_INT_MIXER: 'Míchací moduly', MQTT_INT_MIXER: 'Směšovací moduly',
MQTT_INT_WATER: 'Vodní moduly', MQTT_INT_WATER: 'Vodní moduly',
MQTT_QUEUE: 'MQTT fronta', MQTT_QUEUE: 'MQTT fronta',
DEFAULT: 'Výchozí', DEFAULT: 'Výchozí',
@@ -260,8 +259,8 @@ const cz: Translation = {
SCAN_AGAIN: 'Skenovat znovu', SCAN_AGAIN: 'Skenovat znovu',
NETWORK_SCANNER: 'Síťový skener', NETWORK_SCANNER: 'Síťový skener',
NETWORK_NO_WIFI: 'Nenalezeny žádné WiFi sítě', NETWORK_NO_WIFI: 'Nenalezeny žádné WiFi sítě',
NETWORK_BLANK_SSID: 'nechte prázdné pro deaktivaci WiFi a povolení ETH', NETWORK_BLANK_SSID: 'ponechte prázdné pro deaktivaci WiFi a povolení ETH',
NETWORK_BLANK_BSSID: 'nechte prázdné pro použití pouze SSID', NETWORK_BLANK_BSSID: 'ponechte prázdné pokud použijete jen SSID',
TX_POWER: 'Vysílací výkon', TX_POWER: 'Vysílací výkon',
HOSTNAME: 'Název hostitele', HOSTNAME: 'Název hostitele',
NETWORK_DISABLE_SLEEP: 'Zakázat režim spánku WiFi', NETWORK_DISABLE_SLEEP: 'Zakázat režim spánku WiFi',
@@ -332,7 +331,7 @@ const cz: Translation = {
ALLVALUES: 'Všechny hodnoty', ALLVALUES: 'Všechny hodnoty',
SPECIAL_FUNCTIONS: 'Speciální funkce', SPECIAL_FUNCTIONS: 'Speciální funkce',
WAIT_FIRMWARE: 'Firmware se nahrává a instaluje', WAIT_FIRMWARE: 'Firmware se nahrává a instaluje',
INSTALL_VERSION: 'Tímto se nainstaluje verze {0}. Jste si jistí?', INSTALL_VERSION: 'Tímto se instalovat verze {0}. Jste si jistí?',
SWITCH_DEV: 'přepnout na vývojovou verzi', SWITCH_DEV: 'přepnout na vývojovou verzi',
UPGRADE_AVAILABLE: 'Je k dispozici aktualizace firmwaru!', UPGRADE_AVAILABLE: 'Je k dispozici aktualizace firmwaru!',
LATEST_VERSION: 'Používáte nejnovější verzi firmwaru.', LATEST_VERSION: 'Používáte nejnovější verzi firmwaru.',
@@ -343,7 +342,8 @@ const cz: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'Žádná data nejsou k dispozici', NO_DATA: 'Žádná data nejsou k dispozici',
DASHBOARD_1: 'Přizpůsobte si dashboard označením EMS entit jako Oblíbené pomocí modulu Přizpůsobení', DASHBOARD_1: 'Přizpůsobte si dashboard označením EMS entit jako Oblíbené pomocí modulu Přizpůsobení',
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Režim vývojáře',
UPGRADE: 'Upgrade' // TODO translate
}; };
export default cz; export default cz;

View File

@@ -159,10 +159,9 @@ const de: Translation = {
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server', HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf GitHub', HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf GitHub',
HELP_INFORMATION_4: 'Bitte laden Sie die Systemdetails und hängen Sie sie an das Support-Issue an', HELP_INFORMATION_4: 'Bitte laden Sie die Systemdetails und hängen Sie sie an das Support-Issue an',
HELP_INFORMATION_5: 'Für Hilfe und Fragen wenden Sie sich bitte an Ihren Installateur',
UPLOAD: 'Hochladen', UPLOAD: 'Hochladen',
DOWNLOAD: '{{H|h|h}}erunterladen', DOWNLOAD: '{{H|h|h}}erunterladen',
INSTALL: 'Installieren {0}', INSTALL: 'Installieren',
ABORTED: 'abgebrochen', ABORTED: 'abgebrochen',
FAILED: 'gescheitert', FAILED: 'gescheitert',
SUCCESSFUL: 'erfolgreich', SUCCESSFUL: 'erfolgreich',
@@ -175,9 +174,9 @@ const de: Translation = {
FACTORY_RESET: 'Werkseinstellung', FACTORY_RESET: 'Werkseinstellung',
SYSTEM_FACTORY_TEXT: 'EMS-ESP wurde auf Werkseinstellung gesetzt und startet als Zugangspunkt neu.', SYSTEM_FACTORY_TEXT: 'EMS-ESP wurde auf Werkseinstellung gesetzt und startet als Zugangspunkt neu.',
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher, alle Einstellungen auf Werkseinstellung zu setzen?', SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher, alle Einstellungen auf Werkseinstellung zu setzen?',
AVAILABLE_VERSION: 'Neuesten verfügbaren Versionen',
STABLE: 'Stabil', STABLE: 'Stabil',
DEVELOPMENT: 'Entwicklung', DEVELOPMENT: 'Entwicklung',
EMS_ESP_VER: 'Firmware-Version',
UPTIME: 'Systembetriebszeit', UPTIME: 'Systembetriebszeit',
FREE_MEMORY: 'Freier RAM Speicher', FREE_MEMORY: 'Freier RAM Speicher',
PSRAM: 'PSRAM (Größe / Frei)', PSRAM: 'PSRAM (Größe / Frei)',
@@ -332,7 +331,7 @@ const de: Translation = {
ALLVALUES: 'Alle Werte', ALLVALUES: 'Alle Werte',
SPECIAL_FUNCTIONS: 'Sonderfunktionen', SPECIAL_FUNCTIONS: 'Sonderfunktionen',
WAIT_FIRMWARE: 'Die Firmware wird hochgeladen und installiert.', WAIT_FIRMWARE: 'Die Firmware wird hochgeladen und installiert.',
INSTALL_VERSION: 'Dadurch wird die Version installiert {0}. Sind Sie sicher?', INSTALL_VERSION: 'Dadurch wird die Version {0} heruntergeladen. Sind Sie sicher?',
SWITCH_DEV: 'Wechseln Sie zur Entwicklungsversion!', SWITCH_DEV: 'Wechseln Sie zur Entwicklungsversion!',
UPGRADE_AVAILABLE: 'Es ist ein Firmware-Upgrade verfügbar.', UPGRADE_AVAILABLE: 'Es ist ein Firmware-Upgrade verfügbar.',
LATEST_VERSION: 'Sie verwenden die neueste Firmware-Version.', LATEST_VERSION: 'Sie verwenden die neueste Firmware-Version.',
@@ -343,7 +342,8 @@ const de: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'Keine Daten verfügbar', NO_DATA: 'Keine Daten verfügbar',
DASHBOARD_1: 'Passen Sie Ihr Dashboard an, indem Sie EMS-Entitäten mithilfe des Moduls „Anpassungen“ als Favorit markieren', DASHBOARD_1: 'Passen Sie Ihr Dashboard an, indem Sie EMS-Entitäten mithilfe des Moduls „Anpassungen“ als Favorit markieren',
DEVELOPER_MODE: 'Entwicklermodus' DEVELOPER_MODE: 'Entwicklermodus',
UPGRADE: 'Upgrade' // TODO translate
}; };
export default de; export default de;

View File

@@ -159,10 +159,9 @@ const en: Translation = {
HELP_INFORMATION_2: 'For live community chat join our Discord server', HELP_INFORMATION_2: 'For live community chat join our Discord server',
HELP_INFORMATION_3: 'To request a feature or report a bug', HELP_INFORMATION_3: 'To request a feature or report a bug',
HELP_INFORMATION_4: 'Download and attach your support information for a faster response when reporting an issue', HELP_INFORMATION_4: 'Download and attach your support information for a faster response when reporting an issue',
HELP_INFORMATION_5: 'For help and questions please contact your installer',
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
INSTALL: 'Install {0}', INSTALL: 'Install',
ABORTED: 'aborted', ABORTED: 'aborted',
FAILED: 'failed', FAILED: 'failed',
SUCCESSFUL: 'successful', SUCCESSFUL: 'successful',
@@ -175,9 +174,9 @@ const en: Translation = {
FACTORY_RESET: 'Factory Reset', FACTORY_RESET: 'Factory Reset',
SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart', SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart',
SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?', SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?',
AVAILABLE_VERSION: 'Latest Available Versions',
STABLE: 'Stable', STABLE: 'Stable',
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
EMS_ESP_VER: 'Firmware Version',
UPTIME: 'System Uptime', UPTIME: 'System Uptime',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
PSRAM: 'PSRAM (Size / Free)', PSRAM: 'PSRAM (Size / Free)',
@@ -187,7 +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',
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
UPLOAD_DROP_TEXT: 'Drop file or click here', UPLOAD_DROP_TEXT: 'Drop file or click here',
ERROR: 'Unexpected Error, please try again', ERROR: 'Unexpected Error, please try again',
TIME_SET: 'Time set', TIME_SET: 'Time set',
@@ -343,7 +342,8 @@ const en: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'No data available', NO_DATA: 'No data available',
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module',
DEVELOPER_MODE: 'Developer Mode' DEVELOPER_MODE: 'Developer Mode',
UPGRADE: 'Upgrade'
}; };
export default en; export default en;

View File

@@ -159,10 +159,9 @@ const fr: Translation = {
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord', HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème', HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème',
HELP_INFORMATION_4: "N'oubliez pas de télécharger et de joindre les informations relatives à votre système pour obtenir une réponse plus rapide lorsque vous signalez un problème", HELP_INFORMATION_4: "N'oubliez pas de télécharger et de joindre les informations relatives à votre système pour obtenir une réponse plus rapide lorsque vous signalez un problème",
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
INSTALL: 'Installer {0}', INSTALL: 'Installer',
ABORTED: 'annulé', ABORTED: 'annulé',
FAILED: 'échoué', FAILED: 'échoué',
SUCCESSFUL: 'réussi', SUCCESSFUL: 'réussi',
@@ -175,9 +174,9 @@ const fr: Translation = {
FACTORY_RESET: 'Réinitialisation', FACTORY_RESET: 'Réinitialisation',
SYSTEM_FACTORY_TEXT: "L'appareil a été réinitialisé et va maintenant redémarrer", SYSTEM_FACTORY_TEXT: "L'appareil a été réinitialisé et va maintenant redémarrer",
SYSTEM_FACTORY_TEXT_DIALOG: "Êtes-vous sûr de vouloir réinitialiser l'appareil à ses paramètres d'usine ?", SYSTEM_FACTORY_TEXT_DIALOG: "Êtes-vous sûr de vouloir réinitialiser l'appareil à ses paramètres d'usine ?",
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Développement', DEVELOPMENT: 'Développement',
EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'Durée de fonctionnement du système', UPTIME: 'Durée de fonctionnement du système',
FREE_MEMORY: 'Libre Memory', FREE_MEMORY: 'Libre Memory',
PSRAM: 'PSRAM (Taille / Libre)', PSRAM: 'PSRAM (Taille / Libre)',
@@ -187,7 +186,7 @@ const fr: Translation = {
BUFFER_SIZE: 'Max taille du buffer', BUFFER_SIZE: 'Max taille du buffer',
COMPACT: 'Compact', COMPACT: 'Compact',
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Déposer le fichier ou cliquer ici', UPLOAD_DROP_TEXT: 'Déposer le fichier ou cliquer ici',
ERROR: 'Erreur inattendue, veuillez réessayer', ERROR: 'Erreur inattendue, veuillez réessayer',
TIME_SET: 'Time set', TIME_SET: 'Time set',
@@ -343,7 +342,8 @@ const fr: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default fr; export default fr;

View File

@@ -159,7 +159,6 @@ const it: Translation = {
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord', HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore', HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore',
HELP_INFORMATION_4: 'Ricordati di scaricare e allegare le informazioni del tuo sistema per una risposta più rapida quando segnali un problema', HELP_INFORMATION_4: 'Ricordati di scaricare e allegare le informazioni del tuo sistema per una risposta più rapida quando segnali un problema',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Carica', UPLOAD: 'Carica',
DOWNLOAD: 'Scarica', DOWNLOAD: 'Scarica',
INSTALL: 'Installare {0}', INSTALL: 'Installare {0}',
@@ -175,9 +174,9 @@ const it: Translation = {
FACTORY_RESET: 'Impostazioni di fabbrica', FACTORY_RESET: 'Impostazioni di fabbrica',
SYSTEM_FACTORY_TEXT: 'Il dispositivo è stato ripristinato alle impostazioni di fabbrica e ora verrà riavviato', SYSTEM_FACTORY_TEXT: 'Il dispositivo è stato ripristinato alle impostazioni di fabbrica e ora verrà riavviato',
SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??', SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Sviluppo', DEVELOPMENT: 'Sviluppo',
EMS_ESP_VER: 'Versione Firmware',
UPTIME: 'Tempo di attività del sistema', UPTIME: 'Tempo di attività del sistema',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
PSRAM: 'PSRAM (Size / Free)', PSRAM: 'PSRAM (Size / Free)',
@@ -187,7 +186,7 @@ const it: 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', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Trascina il file o clicca qui', UPLOAD_DROP_TEXT: 'Trascina il file o clicca qui',
ERROR: 'Errore Inaspettato, prego tenta ancora', ERROR: 'Errore Inaspettato, prego tenta ancora',
TIME_SET: 'Imposta Ora', TIME_SET: 'Imposta Ora',
@@ -343,7 +342,8 @@ const it: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default it; export default it;

View File

@@ -159,10 +159,9 @@ const nl: Translation = {
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server', HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren', HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren',
HELP_INFORMATION_4: 'Zorg dat je ook je systeem details zijn toevoeged voor een sneller antwoord', HELP_INFORMATION_4: 'Zorg dat je ook je systeem details zijn toevoeged voor een sneller antwoord',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
INSTALL: 'Installeren {0}', INSTALL: 'Installeren',
ABORTED: 'afgebroken', ABORTED: 'afgebroken',
FAILED: 'mislukt', FAILED: 'mislukt',
SUCCESSFUL: 'successvol', SUCCESSFUL: 'successvol',
@@ -175,9 +174,9 @@ const nl: Translation = {
FACTORY_RESET: 'Fabrieksinstellingen', FACTORY_RESET: 'Fabrieksinstellingen',
SYSTEM_FACTORY_TEXT: 'Gateway is gereset en start nu weer op met fabrieksinstellingen', SYSTEM_FACTORY_TEXT: 'Gateway is gereset en start nu weer op met fabrieksinstellingen',
SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?', SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', STABLE: 'Stable',
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
EMS_ESP_VER: 'Firmware Versie',
UPTIME: 'Systeem Uptime', UPTIME: 'Systeem Uptime',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
PSRAM: 'PSRAM (Size / Free)', PSRAM: 'PSRAM (Size / Free)',
@@ -187,7 +186,7 @@ const nl: 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', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Sleep bestand hierheen of klik hier', UPLOAD_DROP_TEXT: 'Sleep bestand hierheen of klik hier',
ERROR: 'Onverwachte fout, probeer opnieuw', ERROR: 'Onverwachte fout, probeer opnieuw',
TIME_SET: 'Tijd ingesteld', TIME_SET: 'Tijd ingesteld',
@@ -343,7 +342,8 @@ const nl: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default nl; export default nl;

View File

@@ -159,10 +159,9 @@ const no: Translation = {
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server', HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil', HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil',
HELP_INFORMATION_4: 'Husk å laste ned og legg ved din systeminformasjon for en raskere respons når du rapporterer et problem', HELP_INFORMATION_4: 'Husk å laste ned og legg ved din systeminformasjon for en raskere respons når du rapporterer et problem',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Opplasning', UPLOAD: 'Opplasning',
DOWNLOAD: '{{N|n|n}}edlasting', DOWNLOAD: '{{N|n|n}}edlasting',
INSTALL: 'Installer {0}', INSTALL: 'Installer',
ABORTED: 'avbrutt', ABORTED: 'avbrutt',
FAILED: 'feilet', FAILED: 'feilet',
SUCCESSFUL: 'vellykket', SUCCESSFUL: 'vellykket',
@@ -175,9 +174,9 @@ const no: Translation = {
FACTORY_RESET: 'Sett tilbake til fabrikkinstilling', FACTORY_RESET: 'Sett tilbake til fabrikkinstilling',
SYSTEM_FACTORY_TEXT: 'Enhet har blitt satt tilbake til fabrikkinstilling og vil restarte', SYSTEM_FACTORY_TEXT: 'Enhet har blitt satt tilbake til fabrikkinstilling og vil restarte',
SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?', SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'System Oppetid', UPTIME: 'System Oppetid',
FREE_MEMORY: 'Ledig Memory', FREE_MEMORY: 'Ledig Memory',
PSRAM: 'PSRAM (Størrelse / Ledig)', PSRAM: 'PSRAM (Størrelse / Ledig)',
@@ -187,7 +186,7 @@ const no: Translation = {
BUFFER_SIZE: 'Max Buffer Størrelse', BUFFER_SIZE: 'Max Buffer Størrelse',
COMPACT: 'Komprimere', COMPACT: 'Komprimere',
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Slipp fil eller klikk her', UPLOAD_DROP_TEXT: 'Slipp fil eller klikk her',
ERROR: 'Ukjent feil, prøv igjen', ERROR: 'Ukjent feil, prøv igjen',
TIME_SET: 'Still in tid', TIME_SET: 'Still in tid',
@@ -343,7 +342,8 @@ const no: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default no; export default no;

View File

@@ -159,10 +159,9 @@ const pl: BaseTranslation = {
HELP_INFORMATION_2: 'Dołącz do naszego serwera Discord by komunikować się na żywo ze społecznością', HELP_INFORMATION_2: 'Dołącz do naszego serwera Discord by komunikować się na żywo ze społecznością',
HELP_INFORMATION_3: 'Zaproponuj nową funkcjonalność lub zgłoś problem', HELP_INFORMATION_3: 'Zaproponuj nową funkcjonalność lub zgłoś problem',
HELP_INFORMATION_4: 'Zgłaszając problem, nie zapomnij pobrać i dołączyć informacji o swoim systemie!', HELP_INFORMATION_4: 'Zgłaszając problem, nie zapomnij pobrać i dołączyć informacji o swoim systemie!',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Wysyłanie', UPLOAD: 'Wysyłanie',
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}', DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
INSTALL: 'Zainstalować {0}', INSTALL: 'Zainstalować',
ABORTED: 'zostało przerwane!', ABORTED: 'zostało przerwane!',
FAILED: 'nie powiodł{{o|a|}} się!', FAILED: 'nie powiodł{{o|a|}} się!',
SUCCESSFUL: 'powiodło się.', SUCCESSFUL: 'powiodło się.',
@@ -175,9 +174,9 @@ const pl: BaseTranslation = {
FACTORY_RESET: 'Ustawienia fabryczne', FACTORY_RESET: 'Ustawienia fabryczne',
SYSTEM_FACTORY_TEXT: 'Interfejs EMS-ESP został przywrócony do ustawień fabrycznych i zostanie teraz ponownie uruchomiony.', SYSTEM_FACTORY_TEXT: 'Interfejs EMS-ESP został przywrócony do ustawień fabrycznych i zostanie teraz ponownie uruchomiony.',
SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP?', SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Testowe', DEVELOPMENT: 'Testowe',
EMS_ESP_VER: 'Wersja Firmware',
UPTIME: 'Czas działania systemu', UPTIME: 'Czas działania systemu',
FREE_MEMORY: 'Wolne Memory', FREE_MEMORY: 'Wolne Memory',
PSRAM: 'PSRAM (rozmiar / wolne)', PSRAM: 'PSRAM (rozmiar / wolne)',
@@ -187,7 +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: 'Create a backup of your configuration and settings', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Przeciągnij tutaj plik lub kliknij', UPLOAD_DROP_TEXT: 'Przeciągnij tutaj plik lub kliknij',
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
TIME_SET: 'Zegar został ustawiony.', TIME_SET: 'Zegar został ustawiony.',
@@ -343,7 +342,8 @@ const pl: BaseTranslation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default pl; export default pl;

View File

@@ -159,10 +159,9 @@ const sk: Translation = {
HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server', HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server',
HELP_INFORMATION_3: 'Ak chcete požiadať o funkciu alebo nahlásiť chybu', HELP_INFORMATION_3: 'Ak chcete požiadať o funkciu alebo nahlásiť chybu',
HELP_INFORMATION_4: 'nezabudnite si stiahnuť a pripojiť informácie o vašom systéme, aby ste mohli rýchlejšie reagovať pri nahlasovaní problému', HELP_INFORMATION_4: 'nezabudnite si stiahnuť a pripojiť informácie o vašom systéme, aby ste mohli rýchlejšie reagovať pri nahlasovaní problému',
HELP_INFORMATION_5: 'Pre pomoc a otázky, kontaktujte svojho inštalatéra',
UPLOAD: 'Nahrať', UPLOAD: 'Nahrať',
DOWNLOAD: '{{S|s|s}}tiahnuť', DOWNLOAD: '{{S|s|s}}tiahnuť',
INSTALL: 'Inštalovať {0}', INSTALL: 'Inštalovať',
ABORTED: 'zrušené', ABORTED: 'zrušené',
FAILED: 'chybné', FAILED: 'chybné',
SUCCESSFUL: 'úspešné', SUCCESSFUL: 'úspešné',
@@ -175,9 +174,9 @@ const sk: Translation = {
FACTORY_RESET: 'Továrenské nastavenia', FACTORY_RESET: 'Továrenské nastavenia',
SYSTEM_FACTORY_TEXT: 'Zariadenie bolo obnovené z výroby a teraz sa reštartuje', SYSTEM_FACTORY_TEXT: 'Zariadenie bolo obnovené z výroby a teraz sa reštartuje',
SYSTEM_FACTORY_TEXT_DIALOG: 'Naozaj chcete resetovať EMS-ESP na predvolené výrobné nastavenia?', SYSTEM_FACTORY_TEXT_DIALOG: 'Naozaj chcete resetovať EMS-ESP na predvolené výrobné nastavenia?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stabilná', STABLE: 'Stabilná',
DEVELOPMENT: 'Vývojárska', DEVELOPMENT: 'Vývojárska',
EMS_ESP_VER: 'Firmware verzia',
UPTIME: 'Beh systému', UPTIME: 'Beh systému',
FREE_MEMORY: 'Voľné Memory', FREE_MEMORY: 'Voľné Memory',
PSRAM: 'PSRAM (Veľkosť / Voľné)', PSRAM: 'PSRAM (Veľkosť / Voľné)',
@@ -332,7 +331,7 @@ const sk: Translation = {
ALLVALUES: 'Všetky hodnoty', ALLVALUES: 'Všetky hodnoty',
SPECIAL_FUNCTIONS: 'Špeciálne funkcie', SPECIAL_FUNCTIONS: 'Špeciálne funkcie',
WAIT_FIRMWARE: 'Firmvér sa nahráva a inštaluje', WAIT_FIRMWARE: 'Firmvér sa nahráva a inštaluje',
INSTALL_VERSION: 'Týmto sa nainštaluje verzia {0}. Si si istý?', INSTALL_VERSION: 'Týmto sa inštalovať verzia {0}. Si si istý?',
SWITCH_DEV: 'prejsť na vývojovú verziu', SWITCH_DEV: 'prejsť na vývojovú verziu',
UPGRADE_AVAILABLE: 'K dispozícii je aktualizácia firmvéru!', UPGRADE_AVAILABLE: 'K dispozícii je aktualizácia firmvéru!',
LATEST_VERSION: 'Používate poslednú verziu firmvéru.', LATEST_VERSION: 'Používate poslednú verziu firmvéru.',
@@ -343,7 +342,8 @@ const sk: Translation = {
DASHBOARD: 'Panel', DASHBOARD: 'Panel',
NO_DATA: 'Nie sú k dispozícii žiadne údaje', NO_DATA: 'Nie sú k dispozícii žiadne údaje',
DASHBOARD_1: 'Prispôsobte si svoj informačný panel tak, že označíte entity EMS ako Obľúbené pomocou modulu Prispôsobenia', DASHBOARD_1: 'Prispôsobte si svoj informačný panel tak, že označíte entity EMS ako Obľúbené pomocou modulu Prispôsobenia',
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default sk; export default sk;

View File

@@ -159,10 +159,9 @@ const sv: Translation = {
HELP_INFORMATION_2: 'För community-support besök vår Discord-server', HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg', HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg',
HELP_INFORMATION_4: 'Bifoga din systeminformation för snabbare hantering när du rapporterar ett problem', HELP_INFORMATION_4: 'Bifoga din systeminformation för snabbare hantering när du rapporterar ett problem',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Uppladdning', UPLOAD: 'Uppladdning',
DOWNLOAD: '{{N|n|n}}edladdning', DOWNLOAD: '{{N|n|n}}edladdning',
INSTALL: 'Installera {0}', INSTALL: 'Installera',
ABORTED: 'Avbruten', ABORTED: 'Avbruten',
FAILED: 'Misslyckades', FAILED: 'Misslyckades',
SUCCESSFUL: 'Lyckades', SUCCESSFUL: 'Lyckades',
@@ -175,9 +174,9 @@ const sv: Translation = {
FACTORY_RESET: 'Fabriksåterställning', FACTORY_RESET: 'Fabriksåterställning',
SYSTEM_FACTORY_TEXT: 'Enheten har blivit fabriksåterställd och startar nu om', SYSTEM_FACTORY_TEXT: 'Enheten har blivit fabriksåterställd och startar nu om',
SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?', SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Utveckling', DEVELOPMENT: 'Utveckling',
EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'Systemets Upptid', UPTIME: 'Systemets Upptid',
FREE_MEMORY: 'Ledigt Memory', FREE_MEMORY: 'Ledigt Memory',
PSRAM: 'PSRAM (Storlek / Ledigt)', PSRAM: 'PSRAM (Storlek / Ledigt)',
@@ -187,7 +186,7 @@ const sv: Translation = {
BUFFER_SIZE: 'Max Bufferstorlek', BUFFER_SIZE: 'Max Bufferstorlek',
COMPACT: 'Komprimera', COMPACT: 'Komprimera',
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Släpp fil eller klicka här', UPLOAD_DROP_TEXT: 'Släpp 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',
TIME_SET: 'Ställ in tid', TIME_SET: 'Ställ in tid',
@@ -343,7 +342,8 @@ const sv: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default sv; export default sv;

View File

@@ -159,10 +159,9 @@ const tr: Translation = {
HELP_INFORMATION_2: 'Canlı topluluk sohbeti için Discord sunucumuza katılın', HELP_INFORMATION_2: 'Canlı topluluk sohbeti için Discord sunucumuza katılın',
HELP_INFORMATION_3: 'Yeni bir özellik talep etmek yada hata bildirmek için', HELP_INFORMATION_3: 'Yeni bir özellik talep etmek yada hata bildirmek için',
HELP_INFORMATION_4: 'Bir sorun bildirirken daha hızlı bir dönüş için sistem bilginizi indirip eklemeyi unutmayın', HELP_INFORMATION_4: 'Bir sorun bildirirken daha hızlı bir dönüş için sistem bilginizi indirip eklemeyi unutmayın',
HELP_INFORMATION_5: 'For help and questions please contact your installer', // TODO translate
UPLOAD: 'Yükleme', UPLOAD: 'Yükleme',
DOWNLOAD: '{{İ|i|i}}İndirme', DOWNLOAD: '{{İ|i|i}}İndirme',
INSTALL: 'Düzenlemek {0}', INSTALL: 'Düzenlemek',
ABORTED: 'iptal edildi', ABORTED: 'iptal edildi',
FAILED: 'başarısız', FAILED: 'başarısız',
SUCCESSFUL: 'başarılı', SUCCESSFUL: 'başarılı',
@@ -175,9 +174,9 @@ const tr: Translation = {
FACTORY_RESET: 'Fabrika ayarına dönme', FACTORY_RESET: 'Fabrika ayarına dönme',
SYSTEM_FACTORY_TEXT: 'Cihaz fabrika ayarlarına döndü ve şimdi yendiden başlatılacak', SYSTEM_FACTORY_TEXT: 'Cihaz fabrika ayarlarına döndü ve şimdi yendiden başlatılacak',
SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?', SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?',
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Geliştirme', DEVELOPMENT: 'Geliştirme',
EMS_ESP_VER: 'Firmware Sürümü',
UPTIME: 'Sistem Çalışma Süresi', UPTIME: 'Sistem Çalışma Süresi',
FREE_MEMORY: 'Yığın Memory', FREE_MEMORY: 'Yığın Memory',
PSRAM: 'PSRAM (Boyut / Boş)', PSRAM: 'PSRAM (Boyut / Boş)',
@@ -187,7 +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: 'Create a backup of your configuration and settings', // TODO translate DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
UPLOAD_TEXT: 'Upload a new firmware (.bin) file or a backup file (.json)', // TODO translate UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
UPLOAD_DROP_TEXT: 'Buraya tıklayın yada dosyayı sürükleyip bırakın', UPLOAD_DROP_TEXT: 'Buraya tıklayın yada dosyayı sürükleyip bırakın',
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
TIME_SET: 'Zaman ayarı', TIME_SET: 'Zaman ayarı',
@@ -343,7 +342,8 @@ const tr: Translation = {
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // TODO translate NO_DATA: 'No data available', // TODO translate
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
DEVELOPER_MODE: 'Developer Mode' // TODO translate DEVELOPER_MODE: 'Developer Mode', // TODO translate
UPGRADE: 'Upgrade' // TODO translate
}; };
export default tr; export default tr;

View File

@@ -5,7 +5,7 @@ import {
RouterProvider, RouterProvider,
createBrowserRouter, createBrowserRouter,
createRoutesFromElements createRoutesFromElements
} from 'react-router-dom'; } from 'react-router';
import App from 'App'; import App from 'App';

View File

@@ -34,6 +34,7 @@ export interface NetworkStatusType {
dns_ip_1: string; dns_ip_1: string;
dns_ip_2: string; dns_ip_2: string;
hostname: string; hostname: string;
reconnect_count: number;
} }
export interface NetworkSettingsType { export interface NetworkSettingsType {

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { useBlocker } from 'react-router-dom'; import { useBlocker } from 'react-router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import type { AlovaGenerics, Method } from 'alova'; import type { AlovaGenerics, Method } from 'alova';

View File

@@ -27,5 +27,5 @@
} }
}, },
"include": ["src/**/*", "vite.config.ts"], "include": ["src/**/*", "vite.config.ts"],
"exclude": ["node_modules", "dist", "src/**/*.test.tsx", "src/**/*.test.ts"] "exclude": ["node_modules", "dist"]
} }

View File

@@ -20,7 +20,8 @@ export default defineConfig(({ command, mode }) => {
changeOrigin: true, changeOrigin: true,
secure: false secure: false
}, },
'/rest': 'http://localhost:3080' '/rest': 'http://localhost:3080',
'/gh': 'http://localhost:3080' // mock for GitHub API
} }
} }
}; };
@@ -117,11 +118,7 @@ export default defineConfig(({ command, mode }) => {
manualChunks(id: string) { manualChunks(id: string) {
if (id.includes('node_modules')) { if (id.includes('node_modules')) {
// creating a chunk to react routes deps. Reducing the vendor chunk size // creating a chunk to react routes deps. Reducing the vendor chunk size
if ( if (id.includes('react-router')) {
id.includes('react-router-dom') ||
id.includes('@remix-run') ||
id.includes('react-router')
) {
return '@react-router'; return '@react-router';
} }
return 'vendor'; return 'vendor';

File diff suppressed because it is too large Load Diff

View File

@@ -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.2.0" #define ARDUINOJSON_VERSION "7.2.1"
#define ARDUINOJSON_VERSION_MAJOR 7 #define ARDUINOJSON_VERSION_MAJOR 7
#define ARDUINOJSON_VERSION_MINOR 2 #define ARDUINOJSON_VERSION_MINOR 2
#define ARDUINOJSON_VERSION_REVISION 0 #define ARDUINOJSON_VERSION_REVISION 1
#define ARDUINOJSON_VERSION_MACRO V720 #define ARDUINOJSON_VERSION_MACRO V721
#ifndef ARDUINOJSON_VERSION_NAMESPACE #ifndef ARDUINOJSON_VERSION_NAMESPACE
# define ARDUINOJSON_VERSION_NAMESPACE \ # define ARDUINOJSON_VERSION_NAMESPACE \
ARDUINOJSON_CONCAT5( \ ARDUINOJSON_CONCAT5( \
@@ -323,15 +323,15 @@ template <int Bits>
struct uint_; struct uint_;
template <> template <>
struct uint_<8> { struct uint_<8> {
typedef uint8_t type; using type = uint8_t;
}; };
template <> template <>
struct uint_<16> { struct uint_<16> {
typedef uint16_t type; using type = uint16_t;
}; };
template <> template <>
struct uint_<32> { struct uint_<32> {
typedef uint32_t type; using type = uint32_t;
}; };
template <int Bits> template <int Bits>
using uint_t = typename uint_<Bits>::type; using uint_t = typename uint_<Bits>::type;
@@ -417,11 +417,11 @@ class MemoryPool {
}; };
template <bool Condition, class TrueType, class FalseType> template <bool Condition, class TrueType, class FalseType>
struct conditional { struct conditional {
typedef TrueType type; using type = TrueType;
}; };
template <class TrueType, class FalseType> template <class TrueType, class FalseType>
struct conditional<false, TrueType, FalseType> { struct conditional<false, TrueType, FalseType> {
typedef FalseType type; using type = FalseType;
}; };
template <bool Condition, class TrueType, class FalseType> template <bool Condition, class TrueType, class FalseType>
using conditional_t = using conditional_t =
@@ -430,7 +430,7 @@ template <bool Condition, typename T = void>
struct enable_if {}; struct enable_if {};
template <typename T> template <typename T>
struct enable_if<true, T> { struct enable_if<true, T> {
typedef T type; using type = T;
}; };
template <bool Condition, typename T = void> template <bool Condition, typename T = void>
using enable_if_t = typename enable_if<Condition, T>::type; using enable_if_t = typename enable_if<Condition, T>::type;
@@ -451,8 +451,10 @@ template <typename T, T v>
struct integral_constant { struct integral_constant {
static const T value = v; static const T value = v;
}; };
typedef integral_constant<bool, true> true_type; template <bool B>
typedef integral_constant<bool, false> false_type; using bool_constant = integral_constant<bool, B>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
template <typename T> template <typename T>
struct is_array : false_type {}; struct is_array : false_type {};
template <typename T> template <typename T>
@@ -461,11 +463,11 @@ template <typename T, size_t N>
struct is_array<T[N]> : true_type {}; struct is_array<T[N]> : true_type {};
template <typename T> template <typename T>
struct remove_reference { struct remove_reference {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct remove_reference<T&> { struct remove_reference<T&> {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
using remove_reference_t = typename remove_reference<T>::type; using remove_reference_t = typename remove_reference<T>::type;
@@ -509,7 +511,7 @@ struct is_convertible {
protected: // <- to avoid GCC's "all member functions in class are private" protected: // <- to avoid GCC's "all member functions in class are private"
static int probe(To); static int probe(To);
static char probe(...); static char probe(...);
static From& from_; static const From& from_;
public: public:
static const bool value = sizeof(probe(from_)) == sizeof(int); static const bool value = sizeof(probe(from_)) == sizeof(int);
}; };
@@ -527,19 +529,19 @@ template <typename T>
struct is_same<T, T> : true_type {}; struct is_same<T, T> : true_type {};
template <typename T> template <typename T>
struct remove_cv { struct remove_cv {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct remove_cv<const T> { struct remove_cv<const T> {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct remove_cv<volatile T> { struct remove_cv<volatile T> {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct remove_cv<const volatile T> { struct remove_cv<const volatile T> {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
using remove_cv_t = typename remove_cv<T>::type; using remove_cv_t = typename remove_cv<T>::type;
@@ -592,7 +594,7 @@ struct is_unsigned : integral_constant<bool,
is_same<remove_cv_t<T>, bool>::value> {}; is_same<remove_cv_t<T>, bool>::value> {};
template <typename T> template <typename T>
struct type_identity { struct type_identity {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct make_unsigned; struct make_unsigned;
@@ -622,11 +624,11 @@ template <typename T>
using make_unsigned_t = typename make_unsigned<T>::type; using make_unsigned_t = typename make_unsigned<T>::type;
template <typename T> template <typename T>
struct remove_const { struct remove_const {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
struct remove_const<const T> { struct remove_const<const T> {
typedef T type; using type = T;
}; };
template <typename T> template <typename T>
using remove_const_t = typename remove_const<T>::type; using remove_const_t = typename remove_const<T>::type;
@@ -964,16 +966,6 @@ class ZeroTerminatedRamString {
const char* data() const { const char* data() const {
return str_; return str_;
} }
friend int stringCompare(ZeroTerminatedRamString a,
ZeroTerminatedRamString b) {
ARDUINOJSON_ASSERT(!a.isNull());
ARDUINOJSON_ASSERT(!b.isNull());
return ::strcmp(a.str_, b.str_);
}
friend bool stringEquals(ZeroTerminatedRamString a,
ZeroTerminatedRamString b) {
return stringCompare(a, b) == 0;
}
bool isLinked() const { bool isLinked() const {
return false; return false;
} }
@@ -982,14 +974,14 @@ class ZeroTerminatedRamString {
}; };
template <typename TChar> template <typename TChar>
struct StringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> { struct StringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> {
typedef ZeroTerminatedRamString AdaptedString; using AdaptedString = ZeroTerminatedRamString;
static AdaptedString adapt(const TChar* p) { static AdaptedString adapt(const TChar* p) {
return AdaptedString(reinterpret_cast<const char*>(p)); return AdaptedString(reinterpret_cast<const char*>(p));
} }
}; };
template <typename TChar, size_t N> template <typename TChar, size_t N>
struct StringAdapter<TChar[N], enable_if_t<IsChar<TChar>::value>> { struct StringAdapter<TChar[N], enable_if_t<IsChar<TChar>::value>> {
typedef ZeroTerminatedRamString AdaptedString; using AdaptedString = ZeroTerminatedRamString;
static AdaptedString adapt(const TChar* p) { static AdaptedString adapt(const TChar* p) {
return AdaptedString(reinterpret_cast<const char*>(p)); return AdaptedString(reinterpret_cast<const char*>(p));
} }
@@ -1003,7 +995,7 @@ class StaticStringAdapter : public ZeroTerminatedRamString {
}; };
template <> template <>
struct StringAdapter<const char*, void> { struct StringAdapter<const char*, void> {
typedef StaticStringAdapter AdaptedString; using AdaptedString = StaticStringAdapter;
static AdaptedString adapt(const char* p) { static AdaptedString adapt(const char* p) {
return AdaptedString(p); return AdaptedString(p);
} }
@@ -1035,7 +1027,7 @@ class SizedRamString {
}; };
template <typename TChar> template <typename TChar>
struct SizedStringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> { struct SizedStringAdapter<TChar*, enable_if_t<IsChar<TChar>::value>> {
typedef SizedRamString AdaptedString; using AdaptedString = SizedRamString;
static AdaptedString adapt(const TChar* p, size_t n) { static AdaptedString adapt(const TChar* p, size_t n) {
return AdaptedString(reinterpret_cast<const char*>(p), n); return AdaptedString(reinterpret_cast<const char*>(p), n);
} }
@@ -1107,7 +1099,7 @@ class JsonStringAdapter : public SizedRamString {
}; };
template <> template <>
struct StringAdapter<JsonString> { struct StringAdapter<JsonString> {
typedef JsonStringAdapter AdaptedString; using AdaptedString = JsonStringAdapter;
static AdaptedString adapt(const JsonString& s) { static AdaptedString adapt(const JsonString& s) {
return AdaptedString(s); return AdaptedString(s);
} }
@@ -1150,7 +1142,7 @@ struct StringAdapter<
T, T,
enable_if_t<(string_traits<T>::has_cstr || string_traits<T>::has_data) && enable_if_t<(string_traits<T>::has_cstr || string_traits<T>::has_data) &&
(string_traits<T>::has_length || string_traits<T>::has_size)>> { (string_traits<T>::has_length || string_traits<T>::has_size)>> {
typedef SizedRamString AdaptedString; using AdaptedString = SizedRamString;
static AdaptedString adapt(const T& s) { static AdaptedString adapt(const T& s) {
return AdaptedString(get_data(s), get_size(s)); return AdaptedString(get_data(s), get_size(s));
} }
@@ -1350,14 +1342,14 @@ class FlashString {
}; };
template <> template <>
struct StringAdapter<const __FlashStringHelper*, void> { struct StringAdapter<const __FlashStringHelper*, void> {
typedef FlashString AdaptedString; using AdaptedString = FlashString;
static AdaptedString adapt(const __FlashStringHelper* s) { static AdaptedString adapt(const __FlashStringHelper* s) {
return AdaptedString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0); return AdaptedString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0);
} }
}; };
template <> template <>
struct SizedStringAdapter<const __FlashStringHelper*, void> { struct SizedStringAdapter<const __FlashStringHelper*, void> {
typedef FlashString AdaptedString; using AdaptedString = FlashString;
static AdaptedString adapt(const __FlashStringHelper* s, size_t n) { static AdaptedString adapt(const __FlashStringHelper* s, size_t n) {
return AdaptedString(s, n); return AdaptedString(s, n);
} }
@@ -1616,11 +1608,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*/> {
typedef uint64_t mantissa_type; using mantissa_type = uint64_t;
static const short mantissa_bits = 52; static const short mantissa_bits = 52;
static const mantissa_type mantissa_max = static const mantissa_type mantissa_max =
(mantissa_type(1) << mantissa_bits) - 1; (mantissa_type(1) << mantissa_bits) - 1;
typedef int16_t exponent_type; using exponent_type = int16_t;
static const exponent_type exponent_max = 308; static const exponent_type exponent_max = 308;
static pgm_ptr<T> positiveBinaryPowersOfTen() { static pgm_ptr<T> positiveBinaryPowersOfTen() {
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
@@ -1686,11 +1678,11 @@ struct FloatTraits<T, 8 /*64bits*/> {
}; };
template <typename T> template <typename T>
struct FloatTraits<T, 4 /*32bits*/> { struct FloatTraits<T, 4 /*32bits*/> {
typedef uint32_t mantissa_type; using mantissa_type = uint32_t;
static const short mantissa_bits = 23; static const short mantissa_bits = 23;
static const mantissa_type mantissa_max = static const mantissa_type mantissa_max =
(mantissa_type(1) << mantissa_bits) - 1; (mantissa_type(1) << mantissa_bits) - 1;
typedef int8_t exponent_type; using exponent_type = int8_t;
static const exponent_type exponent_max = 38; static const exponent_type exponent_max = 38;
static pgm_ptr<T> positiveBinaryPowersOfTen() { static pgm_ptr<T> positiveBinaryPowersOfTen() {
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors,
@@ -1777,9 +1769,9 @@ inline TFloat make_float(TFloat m, TExponent e) {
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
typedef double JsonFloat; using JsonFloat = double;
#else #else
typedef float JsonFloat; using JsonFloat = float;
#endif #endif
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
@@ -1996,11 +1988,11 @@ class ArrayData : public CollectionData {
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
typedef int64_t JsonInteger; using JsonInteger = int64_t;
typedef uint64_t JsonUInt; using JsonUInt = uint64_t;
#else #else
typedef long JsonInteger; using JsonInteger = long;
typedef unsigned long JsonUInt; using JsonUInt = unsigned long;
#endif #endif
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ #define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
@@ -2675,15 +2667,15 @@ template <typename T>
struct VariantTo {}; struct VariantTo {};
template <> template <>
struct VariantTo<JsonArray> { struct VariantTo<JsonArray> {
typedef JsonArray type; using type = JsonArray;
}; };
template <> template <>
struct VariantTo<JsonObject> { struct VariantTo<JsonObject> {
typedef JsonObject type; using type = JsonObject;
}; };
template <> template <>
struct VariantTo<JsonVariant> { struct VariantTo<JsonVariant> {
typedef JsonVariant type; using type = JsonVariant;
}; };
class VariantAttorney { class VariantAttorney {
public: public:
@@ -3008,7 +3000,7 @@ class JsonVariantConst : public detail::VariantTag,
if (key.template is<size_t>()) if (key.template is<size_t>())
return operator[](key.template as<size_t>()); return operator[](key.template as<size_t>());
else else
return operator[](key.template as<const char*>()); return operator[](key.template as<JsonString>());
} }
template <typename TString> template <typename TString>
ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead") ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead")
@@ -3155,7 +3147,7 @@ class VariantRefBase : public VariantTag {
if (key.template is<size_t>()) if (key.template is<size_t>())
return operator[](key.template as<size_t>()); return operator[](key.template as<size_t>());
else else
return operator[](key.template as<const char*>()); return operator[](key.template as<JsonString>());
} }
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead") ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() const; JsonVariant add() const;
@@ -3392,7 +3384,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
friend class JsonArray; friend class JsonArray;
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
public: public:
typedef JsonArrayConstIterator iterator; using iterator = JsonArrayConstIterator;
iterator begin() const { iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
@@ -3468,7 +3460,7 @@ class JsonObject;
class JsonArray : public detail::VariantOperators<JsonArray> { class JsonArray : public detail::VariantOperators<JsonArray> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
public: public:
typedef JsonArrayIterator iterator; using iterator = JsonArrayIterator;
JsonArray() : data_(0), resources_(0) {} JsonArray() : data_(0), resources_(0) {}
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources) JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : data_(data), resources_(resources) {}
@@ -3687,7 +3679,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
friend class JsonObject; friend class JsonObject;
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
public: public:
typedef JsonObjectConstIterator iterator; using iterator = JsonObjectConstIterator;
JsonObjectConst() : data_(0), resources_(0) {} JsonObjectConst() : data_(0), resources_(0) {}
JsonObjectConst(const detail::ObjectData* data, JsonObjectConst(const detail::ObjectData* data,
const detail::ResourceManager* resources) const detail::ResourceManager* resources)
@@ -3751,8 +3743,8 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
template <typename TVariant> template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst> detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
operator[](const TVariant& key) const { operator[](const TVariant& key) const {
if (key.template is<const char*>()) if (key.template is<JsonString>())
return operator[](key.template as<const char*>()); return operator[](key.template as<JsonString>());
else else
return JsonVariantConst(); return JsonVariantConst();
} }
@@ -3835,7 +3827,7 @@ class JsonArray;
class JsonObject : public detail::VariantOperators<JsonObject> { class JsonObject : public detail::VariantOperators<JsonObject> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
public: public:
typedef JsonObjectIterator iterator; using iterator = JsonObjectIterator;
JsonObject() : data_(0), resources_(0) {} JsonObject() : data_(0), resources_(0) {}
JsonObject(detail::ObjectData* data, detail::ResourceManager* resource) JsonObject(detail::ObjectData* data, detail::ResourceManager* resource)
: data_(data), resources_(resource) {} : data_(data), resources_(resource) {}
@@ -3897,10 +3889,10 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
} }
template <typename TVariant> template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, detail::enable_if_t<detail::IsVariant<TVariant>::value,
detail::MemberProxy<JsonObject, const char*>> detail::MemberProxy<JsonObject, JsonString>>
operator[](const TVariant& key) const { operator[](const TVariant& key) const {
if (key.template is<const char*>()) if (key.template is<JsonString>())
return {*this, key.template as<const char*>()}; return {*this, key.template as<JsonString>()};
else else
return {*this, nullptr}; return {*this, nullptr};
} }
@@ -4059,6 +4051,10 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
const T& src) { const T& src) {
return to<JsonVariant>().set(src); return to<JsonVariant>().set(src);
} }
template <typename TChar>
bool set(TChar* src) {
return to<JsonVariant>().set(src);
}
template <typename T> template <typename T>
typename detail::VariantTo<T>::type to() { typename detail::VariantTo<T>::type to() {
clear(); clear();
@@ -4117,8 +4113,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
template <typename TVariant> template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst> detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
operator[](const TVariant& key) const { operator[](const TVariant& key) const {
if (key.template is<const char*>()) if (key.template is<JsonString>())
return operator[](key.template as<const char*>()); return operator[](key.template as<JsonString>());
if (key.template is<size_t>()) if (key.template is<size_t>())
return operator[](key.template as<size_t>()); return operator[](key.template as<size_t>());
return {}; return {};
@@ -4238,7 +4234,7 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TResult> template <typename TResult>
struct VariantDataVisitor { struct VariantDataVisitor {
typedef TResult result_type; using result_type = TResult;
template <typename T> template <typename T>
TResult visit(const T&) { TResult visit(const T&) {
return TResult(); return TResult();
@@ -4246,7 +4242,7 @@ struct VariantDataVisitor {
}; };
template <typename TResult> template <typename TResult>
struct JsonVariantVisitor { struct JsonVariantVisitor {
typedef TResult result_type; using result_type = TResult;
template <typename T> template <typename T>
TResult visit(const T&) { TResult visit(const T&) {
return TResult(); return TResult();
@@ -4822,7 +4818,7 @@ struct FloatParts {
}; };
template <typename TFloat> template <typename TFloat>
inline int16_t normalize(TFloat& value) { inline int16_t normalize(TFloat& value) {
typedef FloatTraits<TFloat> traits; using traits = FloatTraits<TFloat>;
int16_t powersOf10 = 0; int16_t powersOf10 = 0;
int8_t index = sizeof(TFloat) == 8 ? 8 : 5; int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
int bit = 1 << index; int bit = 1 << index;
@@ -4965,7 +4961,7 @@ class TextFormatter {
} }
template <typename T> template <typename T>
enable_if_t<is_signed<T>::value> writeInteger(T value) { enable_if_t<is_signed<T>::value> writeInteger(T value) {
typedef make_unsigned_t<T> unsigned_type; using unsigned_type = make_unsigned_t<T>;
unsigned_type unsigned_value; unsigned_type unsigned_value;
if (value < 0) { if (value < 0) {
writeRaw('-'); writeRaw('-');
@@ -5703,7 +5699,7 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class JsonVariantCopier { class JsonVariantCopier {
public: public:
typedef bool result_type; using result_type = bool;
JsonVariantCopier(JsonVariant dst) : dst_(dst) {} JsonVariantCopier(JsonVariant dst) : dst_(dst) {}
template <typename T> template <typename T>
bool visit(T src) { bool visit(T src) {
@@ -6325,13 +6321,10 @@ template <typename T, typename... Rest>
struct first_or_void<T, Rest...> { struct first_or_void<T, Rest...> {
using type = T; using type = T;
}; };
template <class T, class = void>
struct is_deserialize_destination : false_type {};
template <class T> template <class T>
struct is_deserialize_destination< using is_deserialize_destination =
T, enable_if_t<is_same<decltype(VariantAttorney::getResourceManager( bool_constant<is_base_of<JsonDocument, remove_cv_t<T>>::value ||
detail::declval<T&>())), IsVariant<T>::value>;
ResourceManager*>::value>> : true_type {};
template <typename TDestination> template <typename TDestination>
inline void shrinkJsonDocument(TDestination&) { inline void shrinkJsonDocument(TDestination&) {
} }
@@ -6571,9 +6564,9 @@ class Number {
#endif #endif
}; };
inline Number parseNumber(const char* s) { inline Number parseNumber(const char* s) {
typedef FloatTraits<JsonFloat> traits; using traits = FloatTraits<JsonFloat>;
typedef largest_type<traits::mantissa_type, JsonUInt> mantissa_t; using mantissa_t = largest_type<traits::mantissa_type, JsonUInt>;
typedef traits::exponent_type exponent_t; using exponent_t = traits::exponent_type;
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s != 0);
bool is_negative = false; bool is_negative = false;
switch (*s) { switch (*s) {
@@ -7212,7 +7205,7 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter> template <typename TWriter>
class PrettyJsonSerializer : public JsonSerializer<TWriter> { class PrettyJsonSerializer : public JsonSerializer<TWriter> {
typedef JsonSerializer<TWriter> base; using base = JsonSerializer<TWriter>;
public: public:
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources) PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
: base(writer, resources), nesting_(0) {} : base(writer, resources), nesting_(0) {}

View File

@@ -1,4 +1,4 @@
Version 7.2.0 Version 7.2.1
From https://github.com/bblanchon/ArduinoJson/releases From https://github.com/bblanchon/ArduinoJson/releases

View File

@@ -7,7 +7,8 @@
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Print.h> #include <Print.h>
constexpr const char * JSON_MIMETYPE = "application/json"; constexpr const char * JSON_MIMETYPE = "application/json";
constexpr const char * MSGPACK_MIMETYPE = "application/msgpack";
class ChunkPrint : public Print { class ChunkPrint : public Print {
private: private:
@@ -54,7 +55,7 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
: _isValid{false} : _isValid{false}
, _isMsgPack{isMsgPack} { , _isMsgPack{isMsgPack} {
_code = 200; _code = 200;
_contentType = JSON_MIMETYPE; _contentType = (isMsgPack) ? MSGPACK_MIMETYPE : JSON_MIMETYPE;
if (isArray) if (isArray)
_root = _jsonBuffer.add<JsonArray>(); _root = _jsonBuffer.add<JsonArray>();
else else

View File

@@ -57,15 +57,15 @@ class ESP8266React {
// special functions needed outside scope // special functions needed outside scope
// //
void setWill(const char * will_topic) {
_mqttSettingsService.setWill(will_topic);
}
// true if AP is active // true if AP is active
bool apStatus() { bool apStatus() {
return _apSettingsService.getAPNetworkStatus() == APNetworkStatus::ACTIVE; return _apSettingsService.getAPNetworkStatus() == APNetworkStatus::ACTIVE;
} }
uint16_t getWifiReconnects() {
return _networkSettingsService.getWifiReconnects();
}
private: private:
SecuritySettingsService _securitySettingsService; SecuritySettingsService _securitySettingsService;
NetworkSettingsService _networkSettingsService; NetworkSettingsService _networkSettingsService;

View File

@@ -101,16 +101,6 @@ const char * MqttSettingsService::getClientId() {
return _mqttClient->getClientId(); return _mqttClient->getClientId();
} }
void MqttSettingsService::setWill(const char * topic) {
#ifndef TASMOTA_SDK
if (_state.enableTLS) {
static_cast<espMqttClientSecure *>(_mqttClient)->setWill(topic, 1, true, "offline");
return;
}
#endif
static_cast<espMqttClient *>(_mqttClient)->setWill(topic, 1, true, "offline");
}
void MqttSettingsService::onMqttMessage(const espMqttClientTypes::MessageProperties & properties, void MqttSettingsService::onMqttMessage(const espMqttClientTypes::MessageProperties & properties,
const char * topic, const char * topic,
const uint8_t * payload, const uint8_t * payload,
@@ -183,6 +173,14 @@ bool MqttSettingsService::configureMqtt() {
// only connect if WiFi is connected and MQTT is enabled // only connect if WiFi is connected and MQTT is enabled
if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) { if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) {
// create last will topic with the base prefixed. It has to be static because the client destroys the reference
static char will_topic[FACTORY_MQTT_MAX_TOPIC_LENGTH];
if (_state.base.isEmpty()) {
snprintf(will_topic, sizeof(will_topic), "status");
} else {
snprintf(will_topic, sizeof(will_topic), "%s/status", _state.base.c_str());
}
_reconfigureMqtt = false; _reconfigureMqtt = false;
#ifndef TASMOTA_SDK #ifndef TASMOTA_SDK
if (_state.enableTLS) { if (_state.enableTLS) {
@@ -197,6 +195,7 @@ bool MqttSettingsService::configureMqtt() {
static_cast<espMqttClientSecure *>(_mqttClient)->setClientId(_state.clientId.c_str()); static_cast<espMqttClientSecure *>(_mqttClient)->setClientId(_state.clientId.c_str());
static_cast<espMqttClientSecure *>(_mqttClient)->setKeepAlive(_state.keepAlive); static_cast<espMqttClientSecure *>(_mqttClient)->setKeepAlive(_state.keepAlive);
static_cast<espMqttClientSecure *>(_mqttClient)->setCleanSession(_state.cleanSession); static_cast<espMqttClientSecure *>(_mqttClient)->setCleanSession(_state.cleanSession);
static_cast<espMqttClientSecure *>(_mqttClient)->setWill(will_topic, 1, true, "offline"); // QOS 1, retain
return _mqttClient->connect(); return _mqttClient->connect();
} }
#endif #endif
@@ -207,6 +206,7 @@ bool MqttSettingsService::configureMqtt() {
static_cast<espMqttClient *>(_mqttClient)->setClientId(_state.clientId.c_str()); static_cast<espMqttClient *>(_mqttClient)->setClientId(_state.clientId.c_str());
static_cast<espMqttClient *>(_mqttClient)->setKeepAlive(_state.keepAlive); static_cast<espMqttClient *>(_mqttClient)->setKeepAlive(_state.keepAlive);
static_cast<espMqttClient *>(_mqttClient)->setCleanSession(_state.cleanSession); static_cast<espMqttClient *>(_mqttClient)->setCleanSession(_state.cleanSession);
static_cast<espMqttClient *>(_mqttClient)->setWill(will_topic, 1, true, "offline"); // QOS 1, retain
return _mqttClient->connect(); return _mqttClient->connect();
} }

View File

@@ -101,7 +101,6 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
const char * getClientId(); const char * getClientId();
espMqttClientTypes::DisconnectReason getDisconnectReason(); espMqttClientTypes::DisconnectReason getDisconnectReason();
MqttClient * getMqttClient(); MqttClient * getMqttClient();
void setWill(const char * topic);
protected: protected:
void onConfigUpdated(); void onConfigUpdated();

View File

@@ -304,10 +304,14 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
break; break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
emsesp::EMSESP::logger().warning("WiFi disconnected. Reason: %s (%d)", connectcount_++; // count the number of WiFi reconnects
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
connectcount_,
disconnectReason(info.wifi_sta_disconnected.reason), disconnectReason(info.wifi_sta_disconnected.reason),
info.wifi_sta_disconnected.reason); // IDF 4.0 info.wifi_sta_disconnected.reason); // IDF 4.0
emsesp::EMSESP::system_.has_ipv6(false); emsesp::EMSESP::system_.has_ipv6(false);
break; break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP:

View File

@@ -87,7 +87,6 @@ class NetworkSettings {
static StateUpdateResult update(JsonObject root, NetworkSettings & settings); static StateUpdateResult update(JsonObject root, NetworkSettings & settings);
}; };
class NetworkSettingsService : public StatefulService<NetworkSettings> { class NetworkSettingsService : public StatefulService<NetworkSettings> {
public: public:
NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
@@ -95,6 +94,10 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
void begin(); void begin();
void loop(); void loop();
uint16_t getWifiReconnects() const {
return connectcount_;
}
private: private:
HttpEndpoint<NetworkSettings> _httpEndpoint; HttpEndpoint<NetworkSettings> _httpEndpoint;
FSPersistence<NetworkSettings> _fsPersistence; FSPersistence<NetworkSettings> _fsPersistence;
@@ -102,6 +105,8 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
unsigned long _lastConnectionAttempt; unsigned long _lastConnectionAttempt;
bool _stopping; bool _stopping;
uint16_t connectcount_ = 0; // number of wifi reconnects
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
void mDNS_start() const; void mDNS_start() const;
const char * disconnectReason(uint8_t code); const char * disconnectReason(uint8_t code);

View File

@@ -60,12 +60,13 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
#else #else
root["local_ipv6"] = WiFi.linkLocalIPv6().toString(); root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
#endif #endif
root["mac_address"] = WiFi.macAddress(); root["mac_address"] = WiFi.macAddress();
root["rssi"] = WiFi.RSSI(); root["rssi"] = WiFi.RSSI();
root["ssid"] = WiFi.SSID(); root["ssid"] = WiFi.SSID();
root["bssid"] = WiFi.BSSIDstr(); root["bssid"] = WiFi.BSSIDstr();
root["channel"] = WiFi.channel(); root["channel"] = WiFi.channel();
root["subnet_mask"] = WiFi.subnetMask().toString(); root["reconnect_count"] = emsesp::EMSESP::esp8266React.getWifiReconnects();
root["subnet_mask"] = WiFi.subnetMask().toString();
if (WiFi.gatewayIP() != INADDR_NONE) { if (WiFi.gatewayIP() != INADDR_NONE) {
root["gateway_ip"] = WiFi.gatewayIP().toString(); root["gateway_ip"] = WiFi.gatewayIP().toString();

View File

@@ -13,7 +13,7 @@
#define UPLOAD_FILE_PATH "/rest/uploadFile" #define UPLOAD_FILE_PATH "/rest/uploadFile"
#define TEMP_FILENAME_PATH "/tmp_upload" // for uploaded json files #define TEMP_FILENAME_PATH "/pre_load.json" // for uploaded json files, handled by System::check_restore()
class UploadFileService { class UploadFileService {
public: public:

View File

@@ -36,6 +36,9 @@ class EMSuart {
static void restart(); static void restart();
static void send_poll(uint8_t data); static void send_poll(uint8_t data);
static uint16_t transmit(uint8_t * buf, uint8_t len); static uint16_t transmit(uint8_t * buf, uint8_t len);
static uint8_t last_tx_src() {
return 0;
}
private: private:
static char * hextoa(char * result, const uint8_t value); static char * hextoa(char * result, const uint8_t value);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
media/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

934
mock-api/.yarn/releases/yarn-4.5.3.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,3 @@
nodeLinker: node-modules nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.5.3.cjs

View File

@@ -1,6 +1,6 @@
{ {
"name": "mock-api", "name": "mock-api",
"version": "3.7.0", "version": "3.7.1",
"description": "mock api for EMS-ESP", "description": "mock api for EMS-ESP",
"author": "proddy, emsesp.org", "author": "proddy, emsesp.org",
"license": "MIT", "license": "MIT",
@@ -13,7 +13,7 @@
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"formidable": "^3.5.2", "formidable": "^3.5.2",
"itty-router": "^5.0.18", "itty-router": "^5.0.18",
"prettier": "^3.3.3" "prettier": "^3.4.1"
}, },
"packageManager": "yarn@4.5.1" "packageManager": "yarn@4.5.3"
} }

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