mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86e29515e7 | ||
|
|
46eb4185d7 | ||
|
|
8da6761a48 | ||
|
|
9233f0dfcc | ||
|
|
292f743b14 | ||
|
|
dd6dfffd57 | ||
|
|
ec705a5307 | ||
|
|
f45f071710 | ||
|
|
f3858546de | ||
|
|
d0ac0b7804 | ||
|
|
d8284ec09f | ||
|
|
6e982acde8 | ||
|
|
8c94ce99b2 | ||
|
|
fc057d18c9 | ||
|
|
18e9b99413 | ||
|
|
a47e0e8266 | ||
|
|
f412ddc716 | ||
|
|
29110e96e5 | ||
|
|
b65866217a | ||
|
|
611e3b1243 | ||
|
|
2ca0a0c634 | ||
|
|
7eb1f061b7 | ||
|
|
50459a23fe | ||
|
|
5bf53c3389 | ||
|
|
4b7aa95be3 | ||
|
|
70943f5758 | ||
|
|
3bc280b817 | ||
|
|
62b15a5319 | ||
|
|
8dd18802d6 | ||
|
|
57a516a83a | ||
|
|
a57fdaa4b3 | ||
|
|
4841e42286 | ||
|
|
8c2d2b06ed | ||
|
|
38c8b1b7f0 | ||
|
|
6fb5933a02 | ||
|
|
c0944433be | ||
|
|
478e6362c9 | ||
|
|
4d6354db78 | ||
|
|
beab0f0c77 | ||
|
|
c17749bd22 | ||
|
|
2bad769c5c | ||
|
|
8ad89ca64b | ||
|
|
9244d8daec | ||
|
|
02d01334b2 |
23
.github/workflows/github-releases-to-discord.yml
vendored
23
.github/workflows/github-releases-to-discord.yml
vendored
@@ -1,23 +0,0 @@
|
|||||||
name: 'github-releases-to-discord'
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
github-releases-to-discord:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Github Releases To Discord
|
|
||||||
uses: SethCohen/github-releases-to-discord@v1.13.1
|
|
||||||
with:
|
|
||||||
webhook_url: ${{ secrets.WEBHOOK_URL }}
|
|
||||||
color: '2105893'
|
|
||||||
username: 'Release Changelog'
|
|
||||||
avatar_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png'
|
|
||||||
content: '||@everyone||'
|
|
||||||
footer_title: 'Changelog'
|
|
||||||
footer_icon_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png'
|
|
||||||
footer_timestamp: true
|
|
||||||
9
.github/workflows/pre_release.yml
vendored
9
.github/workflows/pre_release.yml
vendored
@@ -12,10 +12,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
@@ -35,10 +33,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn typesafe-i18n --no-watch
|
yarn run typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn build
|
yarn run build
|
||||||
yarn webUI
|
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.github/workflows/sonar_check.yml
vendored
4
.github/workflows/sonar_check.yml
vendored
@@ -12,9 +12,9 @@ jobs:
|
|||||||
# if: github.repository_owner == 'emsesp'
|
# if: github.repository_owner == 'emsesp'
|
||||||
# if: github.repository == 'emsesp/EMS-ESP32'
|
# if: github.repository == 'emsesp/EMS-ESP32'
|
||||||
env:
|
env:
|
||||||
BUILD_WRAPPER_OUT_DIR: bw-output
|
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
- name: Install sonar-scanner and build-wrapper
|
- name: Install sonar-scanner and build-wrapper
|
||||||
|
|||||||
9
.github/workflows/tagged_release.yml
vendored
9
.github/workflows/tagged_release.yml
vendored
@@ -11,10 +11,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
@@ -30,10 +28,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn typesafe-i18n --no-watch
|
yarn run typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn build
|
yarn run build
|
||||||
yarn webUI
|
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
9
.github/workflows/test_release.yml
vendored
9
.github/workflows/test_release.yml
vendored
@@ -12,10 +12,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
@@ -35,10 +33,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn typesafe-i18n --no-watch
|
yarn run typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn build
|
yarn run build
|
||||||
yarn webUI
|
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -36,8 +36,6 @@ stats.html
|
|||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
!.yarn/sdks
|
!.yarn/sdks
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
yarn.lock
|
|
||||||
interface/analyse.html
|
|
||||||
|
|
||||||
# scripts
|
# scripts
|
||||||
test.sh
|
test.sh
|
||||||
@@ -55,10 +53,8 @@ interface/src/i18n/i18n-util.async.ts
|
|||||||
# sonar
|
# sonar
|
||||||
.scannerwork/
|
.scannerwork/
|
||||||
sonar/
|
sonar/
|
||||||
bw-output/
|
build_wrapper_output_directory/
|
||||||
|
|
||||||
# entity dump results
|
# entity dump results
|
||||||
# dump_entities.csv
|
# dump_entities.csv
|
||||||
# dump_entities.xls*
|
# dump_entities.xls*
|
||||||
|
|
||||||
benchmark/*.log
|
|
||||||
|
|||||||
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@@ -2,6 +2,7 @@
|
|||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
// for the documentation about the extensions.json format
|
// for the documentation about the extensions.json format
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
"arcanis.vscode-zipfs",
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
|
|||||||
53
.vscode/settings.json
vendored
53
.vscode/settings.json
vendored
@@ -4,11 +4,13 @@
|
|||||||
"**/.pnp.*": true
|
"**/.pnp.*": true
|
||||||
},
|
},
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": "explicit"
|
"source.fixAll": true
|
||||||
|
// "source.organizeImports": true
|
||||||
},
|
},
|
||||||
"eslint.nodePath": "interface/.yarn/sdks",
|
"eslint.nodePath": "interface/.yarn/sdks",
|
||||||
"eslint.workingDirectories": ["interface"],
|
"eslint.workingDirectories": ["interface"],
|
||||||
"prettier.prettierPath": "",
|
"prettier.prettierPath": "",
|
||||||
|
"typescript.tsdk": "interface/.yarn/sdks/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.tsx": "typescriptreact",
|
"*.tsx": "typescriptreact",
|
||||||
@@ -25,51 +27,7 @@
|
|||||||
"type_traits": "cpp",
|
"type_traits": "cpp",
|
||||||
"utility": "cpp",
|
"utility": "cpp",
|
||||||
"string": "cpp",
|
"string": "cpp",
|
||||||
"string_view": "cpp",
|
"string_view": "cpp"
|
||||||
"atomic": "cpp",
|
|
||||||
"bitset": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"chrono": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"condition_variable": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cstring": "cpp",
|
|
||||||
"ctime": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"list": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"unordered_set": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"map": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"set": "cpp",
|
|
||||||
"fstream": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iomanip": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"iostream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"mutex": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"sstream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"thread": "cpp",
|
|
||||||
"cinttypes": "cpp",
|
|
||||||
"typeinfo": "cpp"
|
|
||||||
},
|
},
|
||||||
"todo-tree.filtering.excludeGlobs": [
|
"todo-tree.filtering.excludeGlobs": [
|
||||||
"**/vendor/**",
|
"**/vendor/**",
|
||||||
@@ -83,6 +41,5 @@
|
|||||||
"**/*.min.*",
|
"**/*.min.*",
|
||||||
"**/*.map",
|
"**/*.map",
|
||||||
"**/ArduinoJson/**"
|
"**/ArduinoJson/**"
|
||||||
],
|
]
|
||||||
"cSpell.enableFiletypes": ["!cpp"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
86
CHANGELOG.md
86
CHANGELOG.md
@@ -5,88 +5,6 @@ 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.6.4] November 24 2023
|
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
|
||||||
|
|
||||||
Writeable Text entities have moved from type `sensor` to `text` in Home Assistant to make them also editable within an HA dashboard. Examples are `datetime`, `holidays`, `switchtime`, `vacations`, `maintenancedate`... You will need to manually remove any old discovery topics from your MQTT broker using an application like MQTT Explorer.
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- humidity for ventilation devices
|
|
||||||
- telegrams for RC100H, hc2, etc. (seen on discord, not tested)
|
|
||||||
- names for BC400, GB192i.2, read temperatures for low loss header and heatblock [#1317](https://github.com/emsesp/EMS-ESP32/discussions/1317)
|
|
||||||
- option for `forceheatingoff` [#1262](https://github.com/emsesp/EMS-ESP32/issues/1262)
|
|
||||||
- remote thermostat emulation RC100H for RC3xx [#1278](https://github.com/emsesp/EMS-ESP32/discussions/1278)
|
|
||||||
- shower_data MQTT payload contains the timestamp [#1329](https://github.com/emsesp/EMS-ESP32/issues/1329)
|
|
||||||
- HA discovery for writeable text entities [#1337](https://github.com/emsesp/EMS-ESP32/pull/1377)
|
|
||||||
- autodetect board_profile, store in nvs, add telnet command option, add E32V2
|
|
||||||
- heat pump high res energy counters [#1348, #1349. #1350](https://github.com/emsesp/EMS-ESP32/issues/1348)
|
|
||||||
- optional bssid in network settings
|
|
||||||
- extension module EM100 [#1315](https://github.com/emsesp/EMS-ESP32/discussions/1315)
|
|
||||||
- digital_out with new options for polarity and startup state
|
|
||||||
- added 'system allvalues' command that dumps all the EMS device values, plus sensors and any custom entities
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- remove command `remoteseltemp`, thermostat accept it only from remote thermostat
|
|
||||||
- shower_data MQTT payload contains the timestamp [#1329](https://github.com/emsesp/EMS-ESP32/issues/1329)
|
|
||||||
- fixed helper text in Web Device Entity dialog box for numerical ranges
|
|
||||||
- MQTT base with paths not working in HA [#1393](https://github.com/emsesp/EMS-ESP32/issues/1393)
|
|
||||||
- set/read thermostat mode for RC100-RC300, [#1440](https://github.com/emsesp/EMS-ESP32/issues/1440) [#1442](https://github.com/emsesp/EMS-ESP32/issues/1442)
|
|
||||||
- some setting commands for ems-boiler have used wrong ems+ telegram in 3.6.3
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- update to platform 6.4.0, arduino 2.0.14 / idf 4.4.6
|
|
||||||
- small changes for arduino 3.0.0 / idf 5.1 compatibility (not backward compatible to platform 6.3.2 and before)
|
|
||||||
- AP start after 10 sec, stay until station/eth connected
|
|
||||||
- tested wifi-all-channel-scan (3.6.3-dev4 a-e), removed again because of connect issues
|
|
||||||
- mqtt disconnect stops queue
|
|
||||||
|
|
||||||
## [3.6.2] October 1 2023
|
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- Power entities
|
|
||||||
- Optional input of BSSID for AP connection
|
|
||||||
- Return empty json if no entries in scheduler/custom/analogsensor/temperaturesensor
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- Wifi full scan to get strongest AP
|
|
||||||
- Add missing dhw tags
|
|
||||||
- Sending a dash/- to the Reset command doesn't return an error [#1308](https://github.com/emsesp/EMS-ESP32/discussions/1308)
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- MQTT queue max 300 messages, check heap and maxAlloc
|
|
||||||
- API call commands are logged as WARN in the log
|
|
||||||
- Reset Command renamed to 'reset' in lowercase in EN
|
|
||||||
|
|
||||||
## [3.6.1] September 9 2023
|
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
|
||||||
|
|
||||||
- `shower_data` MQTT topic shows duration is seconds (was previously a full english sentence)
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- Show WiFi rssi in Network Status Page, show quality as color
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- Issue in espMqttClient causing a memory leak when MQTT broker is disconnected due to network unavailability [#1264](https://github.com/emsesp/EMS-ESP32/issues/1264)
|
|
||||||
- Using MQTT enum values correctly formatted in MQTT Discovery [#1280](https://github.com/emsesp/EMS-ESP32/issues/1280)
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- MQTT free mem check set to 60 kb
|
|
||||||
- Small cosmetic changes to Searching in Customization web page
|
|
||||||
- Updated to espressif32@6.4.0
|
|
||||||
|
|
||||||
# [3.6.0] August 13 2023
|
# [3.6.0] August 13 2023
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
@@ -97,7 +15,7 @@ There are breaking changes between 3.5.x and earlier versions of 3.6.0. Please r
|
|||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Workaround for better Domoticz MQTT integration? [#904](https://github.com/emsesp/EMS-ESP32/issues/904)
|
- Workaround for better Domoticz MQTT intergration? [#904](https://github.com/emsesp/EMS-ESP32/issues/904)
|
||||||
- Show MAC address without connecting to network enhancement [#933](https://github.com/emsesp/EMS-ESP32/issues/933)
|
- Show MAC address without connecting to network enhancement [#933](https://github.com/emsesp/EMS-ESP32/issues/933)
|
||||||
- Warn user in WebUI of unsaved changes [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
- Warn user in WebUI of unsaved changes [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
||||||
- Detect old Tado thermostat, device-id 0x19, no entities
|
- Detect old Tado thermostat, device-id 0x19, no entities
|
||||||
@@ -263,7 +181,7 @@ There are breaking changes between 3.5.x and earlier versions of 3.6.0. Please r
|
|||||||
|
|
||||||
- WebUI optimizations, updated look&feel and better performance [#124](https://github.com/emsesp/EMS-ESP32/issues/124)
|
- WebUI optimizations, updated look&feel and better performance [#124](https://github.com/emsesp/EMS-ESP32/issues/124)
|
||||||
- Auto refresh of WebUI after successful firmware upload [#178](https://github.com/emsesp/EMS-ESP32/issues/178)
|
- Auto refresh of WebUI after successful firmware upload [#178](https://github.com/emsesp/EMS-ESP32/issues/178)
|
||||||
- New Customization Service in WebUI. First feature is the ability to enable/disabled Entities (device values) from EMS devices [#206](https://github.com/emsesp/EMS-ESP32/issues/206)
|
- New Customization Service in WebUI. First feature is the ability to enable/disabled Enitites (device values) from EMS devices [#206](https://github.com/emsesp/EMS-ESP32/issues/206)
|
||||||
- Option to disable Telnet Console [#209](https://github.com/emsesp/EMS-ESP32/issues/209)
|
- Option to disable Telnet Console [#209](https://github.com/emsesp/EMS-ESP32/issues/209)
|
||||||
- Added Hide SSID, Max Clients and Preferred Channel to Access Point
|
- Added Hide SSID, Max Clients and Preferred Channel to Access Point
|
||||||
- Merged in MichaelDvP's changes like Fahrenheit conversion, publish single (for IOBroker) and a few other critical optimizations
|
- Merged in MichaelDvP's changes like Fahrenheit conversion, publish single (for IOBroker) and a few other critical optimizations
|
||||||
|
|||||||
@@ -1,24 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [3.6.5]
|
# [3.7.0]
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- thermostat boost mode and boost time [#1446](https://github.com/emsesp/EMS-ESP32/issues/1446)
|
|
||||||
- heatpump energy meters [#1463](https://github.com/emsesp/EMS-ESP32/issues/1463)
|
|
||||||
- heatpump max power [#1475](https://github.com/emsesp/EMS-ESP32/issues/1475)
|
|
||||||
- checkbox for MQTT-TLS enable [#1474](https://github.com/emsesp/EMS-ESP32/issues/1474)
|
|
||||||
- added SK (Slovencina) language. Thanks @misa1515
|
|
||||||
- CPU info [#1497](https://github.com/emsesp/EMS-ESP32/pull/1497)
|
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- exhaust temperature for some boilers
|
|
||||||
- add back boil2hyst [#1477](https://github.com/emsesp/EMS-ESP32/issues/1477)
|
|
||||||
- subscribed MQTT topics not detecting changes by EMS-ESP [#1494](https://github.com/emsesp/EMS-ESP32/issues/1494)
|
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- HA don't set entity_category to Diagnostic/Configuration for EMS entities [#1459](https://github.com/emsesp/EMS-ESP32/discussions/1459)
|
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -42,7 +42,7 @@ DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DAR
|
|||||||
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
|
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
|
||||||
DEFINES += $(ARGS)
|
DEFINES += $(ARGS)
|
||||||
|
|
||||||
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.6.4-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.6.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
@@ -81,7 +81,7 @@ CPPFLAGS += -g3
|
|||||||
CPPFLAGS += -Os
|
CPPFLAGS += -Os
|
||||||
|
|
||||||
CFLAGS += $(CPPFLAGS)
|
CFLAGS += $(CPPFLAGS)
|
||||||
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture -Wno-sign-compare
|
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture
|
||||||
|
|
||||||
CXXFLAGS += $(CFLAGS) -MMD
|
CXXFLAGS += $(CFLAGS) -MMD
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ EMS-ESP is a project owned and maintained by [proddy](https://github.com/proddy)
|
|||||||
- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these open source libraries
|
- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these open source libraries
|
||||||
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON
|
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON
|
||||||
- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client, with custom modifications from @MichaelDvP and @proddy
|
- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client, with custom modifications from @MichaelDvP and @proddy
|
||||||
|
- ESPAsyncWebServer and AsyncTCP for the Web server and TCP backends, with custom modifications for performance
|
||||||
|
|
||||||
## **License**
|
## **License**
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
const url = 'http://10.10.10.135/api/system/commands';
|
|
||||||
const queryParams = {
|
|
||||||
entity: 'commands',
|
|
||||||
id: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const totalRequests = 1000000;
|
|
||||||
const requestsPerCount = 100;
|
|
||||||
|
|
||||||
let requestCount = 0;
|
|
||||||
|
|
||||||
function fetchData() {
|
|
||||||
axios
|
|
||||||
.get(url, { params: queryParams })
|
|
||||||
.then((response) => {
|
|
||||||
requestCount++;
|
|
||||||
|
|
||||||
if (requestCount % requestsPerCount === 0) {
|
|
||||||
console.log(`Requests completed: ${requestCount}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestCount < totalRequests) {
|
|
||||||
fetchData();
|
|
||||||
} else {
|
|
||||||
console.log('All requests completed.');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Error making request:', error.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start making requests
|
|
||||||
console.log(`Starting test`);
|
|
||||||
fetchData();
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Install:
|
|
||||||
# npm install -g autocannon
|
|
||||||
# yarn global add autocannon
|
|
||||||
#
|
|
||||||
# or run https://github.com/nearform/autocannon-ui
|
|
||||||
|
|
||||||
TEST_IP="10.10.10.135"
|
|
||||||
TEST_TIME=60
|
|
||||||
LOG_FILE=http-loadtest.log
|
|
||||||
TIMEOUT=10000
|
|
||||||
PROTOCOL=http
|
|
||||||
#PROTOCOL=https
|
|
||||||
|
|
||||||
if test -f "$LOG_FILE"; then
|
|
||||||
rm $LOG_FILE
|
|
||||||
fi
|
|
||||||
|
|
||||||
# for CONCURRENCY in 1 2 3 4 5 6 7 8 9 10 15 20
|
|
||||||
for CONCURRENCY in 1
|
|
||||||
#for CONCURRENCY in 20
|
|
||||||
do
|
|
||||||
printf "\n\nCLIENTS: *** $CONCURRENCY ***\n\n" >> $LOG_FILE
|
|
||||||
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/"
|
|
||||||
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/" >> $LOG_FILE 2>&1
|
|
||||||
printf "\n\n----------------\n\n" >> $LOG_FILE
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/api/system/commands"
|
|
||||||
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/api/system/commands" >> $LOG_FILE 2>&1
|
|
||||||
printf "\n\n----------------\n\n" >> $LOG_FILE
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
echo "Testing $CONCURRENCY clients on $PROTOCOL://$TEST_IP/app/icon.png"
|
|
||||||
autocannon -c $CONCURRENCY -w 1 -d $TEST_TIME --renderStatusCodes "$PROTOCOL://$TEST_IP/app/icon.png" >> $LOG_FILE 2>&1
|
|
||||||
printf "\n\n----------------\n\n" >> $LOG_FILE
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"autocannon": "^7.14.0",
|
|
||||||
"axios": "^1.6.2",
|
|
||||||
"eventsource": "^2.0.2",
|
|
||||||
"ws": "^8.14.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2338
dump_entities.csv
2338
dump_entities.csv
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"adapter": "react",
|
"adapter": "react",
|
||||||
"baseLocale": "pl",
|
"baseLocale": "pl",
|
||||||
"$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
|
"$schema": "https://unpkg.com/typesafe-i18n@5.26.0/schema/typesafe-i18n.json"
|
||||||
}
|
}
|
||||||
9
interface/.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
Normal file
9
interface/.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
873
interface/.yarn/releases/yarn-3.4.1.cjs
vendored
Executable file
873
interface/.yarn/releases/yarn-3.4.1.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
893
interface/.yarn/releases/yarn-4.0.2.cjs
vendored
893
interface/.yarn/releases/yarn-4.0.2.cjs
vendored
File diff suppressed because one or more lines are too long
20
interface/.yarn/sdks/eslint/bin/eslint.js
vendored
Executable file
20
interface/.yarn/sdks/eslint/bin/eslint.js
vendored
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require eslint/bin/eslint.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real eslint/bin/eslint.js your application uses
|
||||||
|
module.exports = absRequire(`eslint/bin/eslint.js`);
|
||||||
20
interface/.yarn/sdks/eslint/lib/api.js
vendored
Normal file
20
interface/.yarn/sdks/eslint/lib/api.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require eslint
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real eslint your application uses
|
||||||
|
module.exports = absRequire(`eslint`);
|
||||||
6
interface/.yarn/sdks/eslint/package.json
vendored
Normal file
6
interface/.yarn/sdks/eslint/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "eslint",
|
||||||
|
"version": "8.36.0-sdk",
|
||||||
|
"main": "./lib/api.js",
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
5
interface/.yarn/sdks/integrations.yml
vendored
Normal file
5
interface/.yarn/sdks/integrations.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# This file is automatically generated by @yarnpkg/sdks.
|
||||||
|
# Manual changes might be lost!
|
||||||
|
|
||||||
|
integrations:
|
||||||
|
- vscode
|
||||||
20
interface/.yarn/sdks/prettier/index.js
vendored
Executable file
20
interface/.yarn/sdks/prettier/index.js
vendored
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require prettier/index.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real prettier/index.js your application uses
|
||||||
|
module.exports = absRequire(`prettier/index.js`);
|
||||||
6
interface/.yarn/sdks/prettier/package.json
vendored
Normal file
6
interface/.yarn/sdks/prettier/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "prettier",
|
||||||
|
"version": "2.8.7-sdk",
|
||||||
|
"main": "./index.js",
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
20
interface/.yarn/sdks/typescript/bin/tsc
vendored
Executable file
20
interface/.yarn/sdks/typescript/bin/tsc
vendored
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/bin/tsc
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/bin/tsc your application uses
|
||||||
|
module.exports = absRequire(`typescript/bin/tsc`);
|
||||||
20
interface/.yarn/sdks/typescript/bin/tsserver
vendored
Executable file
20
interface/.yarn/sdks/typescript/bin/tsserver
vendored
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/bin/tsserver
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/bin/tsserver your application uses
|
||||||
|
module.exports = absRequire(`typescript/bin/tsserver`);
|
||||||
20
interface/.yarn/sdks/typescript/lib/tsc.js
vendored
Normal file
20
interface/.yarn/sdks/typescript/lib/tsc.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/lib/tsc.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/lib/tsc.js your application uses
|
||||||
|
module.exports = absRequire(`typescript/lib/tsc.js`);
|
||||||
223
interface/.yarn/sdks/typescript/lib/tsserver.js
vendored
Normal file
223
interface/.yarn/sdks/typescript/lib/tsserver.js
vendored
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
const moduleWrapper = tsserver => {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
return tsserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {isAbsolute} = require(`path`);
|
||||||
|
const pnpApi = require(`pnpapi`);
|
||||||
|
|
||||||
|
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
|
||||||
|
const isPortal = str => str.startsWith("portal:/");
|
||||||
|
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
|
||||||
|
|
||||||
|
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
|
||||||
|
return `${locator.name}@${locator.reference}`;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
|
||||||
|
// doesn't understand. This layer makes sure to remove the protocol
|
||||||
|
// before forwarding it to TS, and to add it back on all returned paths.
|
||||||
|
|
||||||
|
function toEditorPath(str) {
|
||||||
|
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
|
||||||
|
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
|
||||||
|
// We also take the opportunity to turn virtual paths into physical ones;
|
||||||
|
// this makes it much easier to work with workspaces that list peer
|
||||||
|
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
|
||||||
|
// file instances instead of the real ones.
|
||||||
|
//
|
||||||
|
// We only do this to modules owned by the the dependency tree roots.
|
||||||
|
// This avoids breaking the resolution when jumping inside a vendor
|
||||||
|
// with peer dep (otherwise jumping into react-dom would show resolution
|
||||||
|
// errors on react).
|
||||||
|
//
|
||||||
|
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
|
||||||
|
if (resolved) {
|
||||||
|
const locator = pnpApi.findPackageLocator(resolved);
|
||||||
|
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
|
||||||
|
str = resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = normalize(str);
|
||||||
|
|
||||||
|
if (str.match(/\.zip\//)) {
|
||||||
|
switch (hostInfo) {
|
||||||
|
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
|
||||||
|
// VSCode only adds it automatically for supported schemes,
|
||||||
|
// so we have to do it manually for the `zip` scheme.
|
||||||
|
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
|
||||||
|
//
|
||||||
|
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
|
||||||
|
//
|
||||||
|
// 2021-10-08: VSCode changed the format in 1.61.
|
||||||
|
// Before | ^zip:/c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
// 2022-04-06: VSCode changed the format in 1.66.
|
||||||
|
// Before | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip/c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
// 2022-05-06: VSCode changed the format in 1.68
|
||||||
|
// Before | ^/zip/c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
case `vscode <1.61`: {
|
||||||
|
str = `^zip:${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode <1.66`: {
|
||||||
|
str = `^/zip/${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode <1.68`: {
|
||||||
|
str = `^/zip${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode`: {
|
||||||
|
str = `^/zip/${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// To make "go to definition" work,
|
||||||
|
// We have to resolve the actual file system path from virtual path
|
||||||
|
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
|
||||||
|
case `coc-nvim`: {
|
||||||
|
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
||||||
|
str = resolve(`zipfile:${str}`);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
|
||||||
|
// We have to resolve the actual file system path from virtual path,
|
||||||
|
// everything else is up to neovim
|
||||||
|
case `neovim`: {
|
||||||
|
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
||||||
|
str = `zipfile://${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
str = `zip:${str}`;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromEditorPath(str) {
|
||||||
|
switch (hostInfo) {
|
||||||
|
case `coc-nvim`: {
|
||||||
|
str = str.replace(/\.zip::/, `.zip/`);
|
||||||
|
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
|
||||||
|
// So in order to convert it back, we use .* to match all the thing
|
||||||
|
// before `zipfile:`
|
||||||
|
return process.platform === `win32`
|
||||||
|
? str.replace(/^.*zipfile:\//, ``)
|
||||||
|
: str.replace(/^.*zipfile:/, ``);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `neovim`: {
|
||||||
|
str = str.replace(/\.zip::/, `.zip/`);
|
||||||
|
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
|
||||||
|
return str.replace(/^zipfile:\/\//, ``);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode`:
|
||||||
|
default: {
|
||||||
|
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force enable 'allowLocalPluginLoads'
|
||||||
|
// TypeScript tries to resolve plugins using a path relative to itself
|
||||||
|
// which doesn't work when using the global cache
|
||||||
|
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
|
||||||
|
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
|
||||||
|
// TypeScript already does local loads and if this code is running the user trusts the workspace
|
||||||
|
// https://github.com/microsoft/vscode/issues/45856
|
||||||
|
const ConfiguredProject = tsserver.server.ConfiguredProject;
|
||||||
|
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
|
||||||
|
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
|
||||||
|
this.projectService.allowLocalPluginLoads = true;
|
||||||
|
return originalEnablePluginsWithOptions.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
// And here is the point where we hijack the VSCode <-> TS communications
|
||||||
|
// by adding ourselves in the middle. We locate everything that looks
|
||||||
|
// like an absolute path of ours and normalize it.
|
||||||
|
|
||||||
|
const Session = tsserver.server.Session;
|
||||||
|
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
|
||||||
|
let hostInfo = `unknown`;
|
||||||
|
|
||||||
|
Object.assign(Session.prototype, {
|
||||||
|
onMessage(/** @type {string | object} */ message) {
|
||||||
|
const isStringMessage = typeof message === 'string';
|
||||||
|
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
|
||||||
|
|
||||||
|
if (
|
||||||
|
parsedMessage != null &&
|
||||||
|
typeof parsedMessage === `object` &&
|
||||||
|
parsedMessage.arguments &&
|
||||||
|
typeof parsedMessage.arguments.hostInfo === `string`
|
||||||
|
) {
|
||||||
|
hostInfo = parsedMessage.arguments.hostInfo;
|
||||||
|
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
|
||||||
|
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
|
||||||
|
// The RegExp from https://semver.org/ but without the caret at the start
|
||||||
|
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
|
||||||
|
) ?? []).map(Number)
|
||||||
|
|
||||||
|
if (major === 1) {
|
||||||
|
if (minor < 61) {
|
||||||
|
hostInfo += ` <1.61`;
|
||||||
|
} else if (minor < 66) {
|
||||||
|
hostInfo += ` <1.66`;
|
||||||
|
} else if (minor < 68) {
|
||||||
|
hostInfo += ` <1.68`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
|
||||||
|
return typeof value === 'string' ? fromEditorPath(value) : value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return originalOnMessage.call(
|
||||||
|
this,
|
||||||
|
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
send(/** @type {any} */ msg) {
|
||||||
|
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
|
||||||
|
return typeof value === `string` ? toEditorPath(value) : value;
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return tsserver;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/lib/tsserver.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/lib/tsserver.js your application uses
|
||||||
|
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`));
|
||||||
223
interface/.yarn/sdks/typescript/lib/tsserverlibrary.js
vendored
Normal file
223
interface/.yarn/sdks/typescript/lib/tsserverlibrary.js
vendored
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
const moduleWrapper = tsserver => {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
return tsserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {isAbsolute} = require(`path`);
|
||||||
|
const pnpApi = require(`pnpapi`);
|
||||||
|
|
||||||
|
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
|
||||||
|
const isPortal = str => str.startsWith("portal:/");
|
||||||
|
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
|
||||||
|
|
||||||
|
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
|
||||||
|
return `${locator.name}@${locator.reference}`;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
|
||||||
|
// doesn't understand. This layer makes sure to remove the protocol
|
||||||
|
// before forwarding it to TS, and to add it back on all returned paths.
|
||||||
|
|
||||||
|
function toEditorPath(str) {
|
||||||
|
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
|
||||||
|
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
|
||||||
|
// We also take the opportunity to turn virtual paths into physical ones;
|
||||||
|
// this makes it much easier to work with workspaces that list peer
|
||||||
|
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
|
||||||
|
// file instances instead of the real ones.
|
||||||
|
//
|
||||||
|
// We only do this to modules owned by the the dependency tree roots.
|
||||||
|
// This avoids breaking the resolution when jumping inside a vendor
|
||||||
|
// with peer dep (otherwise jumping into react-dom would show resolution
|
||||||
|
// errors on react).
|
||||||
|
//
|
||||||
|
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
|
||||||
|
if (resolved) {
|
||||||
|
const locator = pnpApi.findPackageLocator(resolved);
|
||||||
|
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
|
||||||
|
str = resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = normalize(str);
|
||||||
|
|
||||||
|
if (str.match(/\.zip\//)) {
|
||||||
|
switch (hostInfo) {
|
||||||
|
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
|
||||||
|
// VSCode only adds it automatically for supported schemes,
|
||||||
|
// so we have to do it manually for the `zip` scheme.
|
||||||
|
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
|
||||||
|
//
|
||||||
|
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
|
||||||
|
//
|
||||||
|
// 2021-10-08: VSCode changed the format in 1.61.
|
||||||
|
// Before | ^zip:/c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
// 2022-04-06: VSCode changed the format in 1.66.
|
||||||
|
// Before | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip/c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
// 2022-05-06: VSCode changed the format in 1.68
|
||||||
|
// Before | ^/zip/c:/foo/bar.zip/package.json
|
||||||
|
// After | ^/zip//c:/foo/bar.zip/package.json
|
||||||
|
//
|
||||||
|
case `vscode <1.61`: {
|
||||||
|
str = `^zip:${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode <1.66`: {
|
||||||
|
str = `^/zip/${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode <1.68`: {
|
||||||
|
str = `^/zip${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode`: {
|
||||||
|
str = `^/zip/${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// To make "go to definition" work,
|
||||||
|
// We have to resolve the actual file system path from virtual path
|
||||||
|
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
|
||||||
|
case `coc-nvim`: {
|
||||||
|
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
||||||
|
str = resolve(`zipfile:${str}`);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
|
||||||
|
// We have to resolve the actual file system path from virtual path,
|
||||||
|
// everything else is up to neovim
|
||||||
|
case `neovim`: {
|
||||||
|
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
||||||
|
str = `zipfile://${str}`;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
str = `zip:${str}`;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromEditorPath(str) {
|
||||||
|
switch (hostInfo) {
|
||||||
|
case `coc-nvim`: {
|
||||||
|
str = str.replace(/\.zip::/, `.zip/`);
|
||||||
|
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
|
||||||
|
// So in order to convert it back, we use .* to match all the thing
|
||||||
|
// before `zipfile:`
|
||||||
|
return process.platform === `win32`
|
||||||
|
? str.replace(/^.*zipfile:\//, ``)
|
||||||
|
: str.replace(/^.*zipfile:/, ``);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `neovim`: {
|
||||||
|
str = str.replace(/\.zip::/, `.zip/`);
|
||||||
|
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
|
||||||
|
return str.replace(/^zipfile:\/\//, ``);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case `vscode`:
|
||||||
|
default: {
|
||||||
|
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force enable 'allowLocalPluginLoads'
|
||||||
|
// TypeScript tries to resolve plugins using a path relative to itself
|
||||||
|
// which doesn't work when using the global cache
|
||||||
|
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
|
||||||
|
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
|
||||||
|
// TypeScript already does local loads and if this code is running the user trusts the workspace
|
||||||
|
// https://github.com/microsoft/vscode/issues/45856
|
||||||
|
const ConfiguredProject = tsserver.server.ConfiguredProject;
|
||||||
|
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
|
||||||
|
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
|
||||||
|
this.projectService.allowLocalPluginLoads = true;
|
||||||
|
return originalEnablePluginsWithOptions.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
// And here is the point where we hijack the VSCode <-> TS communications
|
||||||
|
// by adding ourselves in the middle. We locate everything that looks
|
||||||
|
// like an absolute path of ours and normalize it.
|
||||||
|
|
||||||
|
const Session = tsserver.server.Session;
|
||||||
|
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
|
||||||
|
let hostInfo = `unknown`;
|
||||||
|
|
||||||
|
Object.assign(Session.prototype, {
|
||||||
|
onMessage(/** @type {string | object} */ message) {
|
||||||
|
const isStringMessage = typeof message === 'string';
|
||||||
|
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
|
||||||
|
|
||||||
|
if (
|
||||||
|
parsedMessage != null &&
|
||||||
|
typeof parsedMessage === `object` &&
|
||||||
|
parsedMessage.arguments &&
|
||||||
|
typeof parsedMessage.arguments.hostInfo === `string`
|
||||||
|
) {
|
||||||
|
hostInfo = parsedMessage.arguments.hostInfo;
|
||||||
|
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
|
||||||
|
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
|
||||||
|
// The RegExp from https://semver.org/ but without the caret at the start
|
||||||
|
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
|
||||||
|
) ?? []).map(Number)
|
||||||
|
|
||||||
|
if (major === 1) {
|
||||||
|
if (minor < 61) {
|
||||||
|
hostInfo += ` <1.61`;
|
||||||
|
} else if (minor < 66) {
|
||||||
|
hostInfo += ` <1.66`;
|
||||||
|
} else if (minor < 68) {
|
||||||
|
hostInfo += ` <1.68`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
|
||||||
|
return typeof value === 'string' ? fromEditorPath(value) : value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return originalOnMessage.call(
|
||||||
|
this,
|
||||||
|
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
send(/** @type {any} */ msg) {
|
||||||
|
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
|
||||||
|
return typeof value === `string` ? toEditorPath(value) : value;
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return tsserver;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/lib/tsserverlibrary.js your application uses
|
||||||
|
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`));
|
||||||
20
interface/.yarn/sdks/typescript/lib/typescript.js
vendored
Normal file
20
interface/.yarn/sdks/typescript/lib/typescript.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {existsSync} = require(`fs`);
|
||||||
|
const {createRequire} = require(`module`);
|
||||||
|
const {resolve} = require(`path`);
|
||||||
|
|
||||||
|
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||||
|
|
||||||
|
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||||
|
const absRequire = createRequire(absPnpApiPath);
|
||||||
|
|
||||||
|
if (existsSync(absPnpApiPath)) {
|
||||||
|
if (!process.versions.pnp) {
|
||||||
|
// Setup the environment to be able to require typescript/lib/typescript.js
|
||||||
|
require(absPnpApiPath).setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer to the real typescript/lib/typescript.js your application uses
|
||||||
|
module.exports = absRequire(`typescript/lib/typescript.js`);
|
||||||
6
interface/.yarn/sdks/typescript/package.json
vendored
Normal file
6
interface/.yarn/sdks/typescript/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "typescript",
|
||||||
|
"version": "5.0.2-sdk",
|
||||||
|
"main": "./lib/typescript.js",
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
compressionLevel: mixed
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
||||||
|
spec: '@yarnpkg/plugin-typescript'
|
||||||
|
|
||||||
enableGlobalCache: false
|
yarnPath: .yarn/releases/yarn-3.4.1.cjs
|
||||||
|
|
||||||
|
# uing pnp
|
||||||
|
# nodeLinker: pnp
|
||||||
|
|
||||||
|
# use these if not using PnP and have node_modules
|
||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
|
compressionLevel: 0
|
||||||
yarnPath: .yarn/releases/yarn-4.0.2.cjs
|
nmMode: hardlinks-local
|
||||||
|
enableGlobalCache: true
|
||||||
|
|||||||
@@ -1,78 +1,79 @@
|
|||||||
{
|
{
|
||||||
"name": "EMS-ESP",
|
"name": "EMS-ESP",
|
||||||
"version": "3.6.5",
|
"version": "3.6.0",
|
||||||
"description": "build EMS-ESP WebUI",
|
"description": "build EMS-ESP WebUI",
|
||||||
"homepage": "https://emsesp.github.io/docs",
|
"homepage": "https://emsesp.github.io/docs",
|
||||||
"author": "proddy",
|
"author": "proddy",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
"build-hosted": "vite build --mode hosted",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
|
"preview-standalone": "npm-run-all -p preview typesafe-i18n mock-api",
|
||||||
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-api\" \"vite preview\"",
|
"mock-api": "nodemon --watch ../mock-api ../mock-api/server.js",
|
||||||
"mock-api": "bun --watch ../mock-api/server.ts",
|
"standalone": "npm-run-all -p dev typesafe-i18n mock-api",
|
||||||
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-api\" \"vite\"",
|
"typesafe-i18n": "typesafe-i18n",
|
||||||
"typesafe-i18n": "typesafe-i18n --no-watch",
|
|
||||||
"webUI": "node progmem-generator.js",
|
|
||||||
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
|
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
|
||||||
"lint": "eslint . --cache --fix"
|
"lint": "eslint . --cache --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alova/adapter-xhr": "^1.0.2",
|
"@alova/adapter-xhr": "^1.0.1",
|
||||||
"@babel/core": "^7.23.7",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/react": "^11.11.3",
|
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5.15.2",
|
"@mui/icons-material": "^5.14.3",
|
||||||
"@mui/material": "^5.15.2",
|
"@mui/material": "^5.14.4",
|
||||||
|
"@preact/compat": "^17.1.2",
|
||||||
|
"@prefresh/vite": "^2.4.1",
|
||||||
"@table-library/react-table-library": "4.1.7",
|
"@table-library/react-table-library": "4.1.7",
|
||||||
"@types/imagemin": "^8.0.5",
|
"@types/lodash-es": "^4.17.8",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/node": "^20.4.10",
|
||||||
"@types/node": "^20.10.6",
|
"@types/react": "^18.2.20",
|
||||||
"@types/react": "^18.2.46",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@types/react-dom": "^18.2.18",
|
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"alova": "^2.16.2",
|
"alova": "^2.10.0",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^3.1.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
|
"preact": "^10.16.0",
|
||||||
"react": "latest",
|
"react": "latest",
|
||||||
"react-dom": "latest",
|
"react-dom": "latest",
|
||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.10.1",
|
||||||
"react-router-dom": "^6.21.1",
|
"react-router-dom": "^6.15.0",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"sockette": "^2.0.6",
|
"sockette": "^2.0.6",
|
||||||
"typesafe-i18n": "^5.26.2",
|
"typesafe-i18n": "^5.26.0",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@preact/compat": "^17.1.2",
|
"@babel/core": "^7.22.10",
|
||||||
"@preact/preset-vite": "^2.7.0",
|
"@preact/preset-vite": "^2.5.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
"@types/babel__core": "^7",
|
||||||
"@typescript-eslint/parser": "^6.17.0",
|
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||||
"concurrently": "^8.2.2",
|
"@typescript-eslint/parser": "^6.3.0",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.47.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint-import-resolver-typescript": "^3.6.0",
|
||||||
"eslint-plugin-autofix": "^1.1.0",
|
"eslint-plugin-autofix": "^1.1.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.28.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||||
"eslint-plugin-prettier": "alpha",
|
"eslint-plugin-prettier": "alpha",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"preact": "^10.19.3",
|
"nodemon": "^3.0.1",
|
||||||
"prettier": "^3.1.1",
|
"npm-run-all": "^4.1.5",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"prettier": "^3.0.1",
|
||||||
"terser": "^5.26.0",
|
"rollup-plugin-visualizer": "^5.9.2",
|
||||||
"vite": "^5.0.10",
|
"terser": "^5.19.2",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite": "^4.4.9",
|
||||||
"vite-tsconfig-paths": "^4.2.3"
|
"vite-plugin-svgr": "^3.2.0",
|
||||||
|
"vite-tsconfig-paths": "^4.2.0"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.0.2"
|
"packageManager": "yarn@3.4.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,10 @@
|
|||||||
import { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } from 'fs';
|
const { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } = require('fs');
|
||||||
import { resolve, relative, sep } from 'path';
|
const { resolve, relative, sep } = require('path');
|
||||||
import zlib from 'zlib';
|
var zlib = require('zlib');
|
||||||
import mime from 'mime-types';
|
var mime = require('mime-types');
|
||||||
|
|
||||||
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
||||||
const INDENT = ' ';
|
const INDENT = ' ';
|
||||||
const outputPath = '../lib/framework/WWWData.h';
|
|
||||||
const sourcePath = './dist';
|
|
||||||
const bytesPerLine = 20;
|
|
||||||
var totalSize = 0;
|
|
||||||
|
|
||||||
const generateWWWClass = () =>
|
|
||||||
`typedef std::function<void(const String &, const String & contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
|
|
||||||
// Total size is ${totalSize} bytes
|
|
||||||
|
|
||||||
class WWWData {
|
|
||||||
${indent}public:
|
|
||||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
|
||||||
${fileInfo
|
|
||||||
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`)
|
|
||||||
.join('\n')}
|
|
||||||
${indent.repeat(2)}}
|
|
||||||
};
|
|
||||||
`;
|
|
||||||
|
|
||||||
function getFilesSync(dir, files = []) {
|
function getFilesSync(dir, files = []) {
|
||||||
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||||
@@ -36,6 +18,10 @@ function getFilesSync(dir, files = []) {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function coherseToBuffer(input) {
|
||||||
|
// return Buffer.isBuffer(input) ? input : Buffer.from(input);
|
||||||
|
// }
|
||||||
|
|
||||||
function cleanAndOpen(path) {
|
function cleanAndOpen(path) {
|
||||||
if (existsSync(path)) {
|
if (existsSync(path)) {
|
||||||
unlinkSync(path);
|
unlinkSync(path);
|
||||||
@@ -43,58 +29,90 @@ function cleanAndOpen(path) {
|
|||||||
return createWriteStream(path, { flags: 'w+' });
|
return createWriteStream(path, { flags: 'w+' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeFile = (relativeFilePath, buffer) => {
|
export default function ProgmemGenerator({ outputPath = './WWWData.h', bytesPerLine = 20 }) {
|
||||||
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
return {
|
||||||
const mimeType = mime.lookup(relativeFilePath);
|
name: 'ProgmemGenerator',
|
||||||
var size = 0;
|
writeBundle: () => {
|
||||||
writeStream.write('const uint8_t ' + variable + '[] = {');
|
console.log('Generating ' + outputPath);
|
||||||
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
const includes = ARDUINO_INCLUDES;
|
||||||
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
const indent = INDENT;
|
||||||
zipBuffer.forEach((b) => {
|
const fileInfo = [];
|
||||||
if (!(size % bytesPerLine)) {
|
const writeStream = cleanAndOpen(resolve(outputPath));
|
||||||
writeStream.write('\n');
|
|
||||||
writeStream.write(indent);
|
|
||||||
}
|
|
||||||
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ',');
|
|
||||||
size++;
|
|
||||||
});
|
|
||||||
if (size % bytesPerLine) {
|
|
||||||
writeStream.write('\n');
|
|
||||||
}
|
|
||||||
writeStream.write('};\n\n');
|
|
||||||
fileInfo.push({
|
|
||||||
uri: '/' + relativeFilePath.replace(sep, '/'),
|
|
||||||
mimeType,
|
|
||||||
variable,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log(relativeFilePath + ' (size ' + size + ' bytes)');
|
try {
|
||||||
totalSize += size;
|
const writeIncludes = () => {
|
||||||
|
writeStream.write(includes);
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeFile = (relativeFilePath, buffer) => {
|
||||||
|
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
||||||
|
const mimeType = mime.lookup(relativeFilePath);
|
||||||
|
var size = 0;
|
||||||
|
writeStream.write('const uint8_t ' + variable + '[] = {');
|
||||||
|
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
||||||
|
const zipBuffer = zlib.gzipSync(buffer);
|
||||||
|
zipBuffer.forEach((b) => {
|
||||||
|
if (!(size % bytesPerLine)) {
|
||||||
|
writeStream.write('\n');
|
||||||
|
writeStream.write(indent);
|
||||||
|
}
|
||||||
|
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).substr(-2) + ',');
|
||||||
|
size++;
|
||||||
|
});
|
||||||
|
if (size % bytesPerLine) {
|
||||||
|
writeStream.write('\n');
|
||||||
|
}
|
||||||
|
writeStream.write('};\n\n');
|
||||||
|
fileInfo.push({
|
||||||
|
uri: '/' + relativeFilePath.replace(sep, '/'),
|
||||||
|
mimeType,
|
||||||
|
variable,
|
||||||
|
size
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeFiles = () => {
|
||||||
|
// process static files
|
||||||
|
const buildPath = resolve('build');
|
||||||
|
for (const filePath of getFilesSync(buildPath)) {
|
||||||
|
const readStream = readFileSync(filePath);
|
||||||
|
const relativeFilePath = relative(buildPath, filePath);
|
||||||
|
writeFile(relativeFilePath, readStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process assets
|
||||||
|
// const { assets } = compilation;
|
||||||
|
// Object.keys(assets).forEach((relativeFilePath) => {
|
||||||
|
// writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateWWWClass = () =>
|
||||||
|
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
|
||||||
|
|
||||||
|
class WWWData {
|
||||||
|
${indent}public:
|
||||||
|
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||||
|
${fileInfo
|
||||||
|
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`)
|
||||||
|
.join('\n')}
|
||||||
|
${indent.repeat(2)}}
|
||||||
};
|
};
|
||||||
|
`;
|
||||||
|
const writeWWWClass = () => {
|
||||||
|
writeStream.write(generateWWWClass());
|
||||||
|
};
|
||||||
|
|
||||||
// start
|
writeIncludes();
|
||||||
console.log('Generating ' + outputPath + ' from ' + sourcePath);
|
writeFiles();
|
||||||
const includes = ARDUINO_INCLUDES;
|
writeWWWClass();
|
||||||
const indent = INDENT;
|
|
||||||
const fileInfo = [];
|
|
||||||
const writeStream = cleanAndOpen(resolve(outputPath));
|
|
||||||
|
|
||||||
// includes
|
writeStream.on('finish', () => {
|
||||||
writeStream.write(includes);
|
// callback();
|
||||||
|
});
|
||||||
// process static files
|
} finally {
|
||||||
const buildPath = resolve(sourcePath);
|
writeStream.end();
|
||||||
for (const filePath of getFilesSync(buildPath)) {
|
}
|
||||||
const readStream = readFileSync(filePath);
|
}
|
||||||
const relativeFilePath = relative(buildPath, filePath);
|
};
|
||||||
writeFile(relativeFilePath, readStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add class
|
|
||||||
writeStream.write(generateWWWClass());
|
|
||||||
|
|
||||||
// end
|
|
||||||
writeStream.end();
|
|
||||||
|
|
||||||
console.log('Total size: ' + totalSize / 1000 + ' KB');
|
|
||||||
|
|||||||
Binary file not shown.
@@ -26,9 +26,6 @@ const theme = responsiveFontSizes(
|
|||||||
},
|
},
|
||||||
info: {
|
info: {
|
||||||
main: '#607d8b' // blueGrey[500]
|
main: '#607d8b' // blueGrey[500]
|
||||||
},
|
|
||||||
text: {
|
|
||||||
disabled: '#eee' // white
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,16 +15,15 @@ import { PROJECT_NAME } from 'api/env';
|
|||||||
import { ValidatedPasswordField, ValidatedTextField } from 'components';
|
import { ValidatedPasswordField, ValidatedTextField } from 'components';
|
||||||
import { AuthenticationContext } from 'contexts/authentication';
|
import { AuthenticationContext } from 'contexts/authentication';
|
||||||
|
|
||||||
import DEflag from 'i18n/DE.svg';
|
import { ReactComponent as DEflag } from 'i18n/DE.svg';
|
||||||
import FRflag from 'i18n/FR.svg';
|
import { ReactComponent as FRflag } from 'i18n/FR.svg';
|
||||||
import GBflag from 'i18n/GB.svg';
|
import { ReactComponent as GBflag } from 'i18n/GB.svg';
|
||||||
import ITflag from 'i18n/IT.svg';
|
import { ReactComponent as ITflag } from 'i18n/IT.svg';
|
||||||
import NLflag from 'i18n/NL.svg';
|
import { ReactComponent as NLflag } from 'i18n/NL.svg';
|
||||||
import NOflag from 'i18n/NO.svg';
|
import { ReactComponent as NOflag } from 'i18n/NO.svg';
|
||||||
import PLflag from 'i18n/PL.svg';
|
import { ReactComponent as PLflag } from 'i18n/PL.svg';
|
||||||
import SKflag from 'i18n/SK.svg';
|
import { ReactComponent as SVflag } from 'i18n/SV.svg';
|
||||||
import SVflag from 'i18n/SV.svg';
|
import { ReactComponent as TRflag } from 'i18n/TR.svg';
|
||||||
import TRflag from 'i18n/TR.svg';
|
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
import { onEnterCallback, updateValue } from 'utils';
|
import { onEnterCallback, updateValue } from 'utils';
|
||||||
@@ -116,43 +115,39 @@ const SignIn: FC = () => {
|
|||||||
|
|
||||||
<TextField name="locale" variant="outlined" value={locale} onChange={onLocaleSelected} size="small" select>
|
<TextField name="locale" variant="outlined" value={locale} onChange={onLocaleSelected} size="small" select>
|
||||||
<MenuItem key="de" value="de">
|
<MenuItem key="de" value="de">
|
||||||
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<DEflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
DE
|
DE
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="en" value="en">
|
<MenuItem key="en" value="en">
|
||||||
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<GBflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
EN
|
EN
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="fr" value="fr">
|
<MenuItem key="fr" value="fr">
|
||||||
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<FRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
FR
|
FR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="it" value="it">
|
<MenuItem key="it" value="it">
|
||||||
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<ITflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
IT
|
IT
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="nl" value="nl">
|
<MenuItem key="nl" value="nl">
|
||||||
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<NLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NL
|
NL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="no" value="no">
|
<MenuItem key="no" value="no">
|
||||||
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<NOflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NO
|
NO
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="pl" value="pl">
|
<MenuItem key="pl" value="pl">
|
||||||
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<PLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
PL
|
PL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="sk" value="sk">
|
|
||||||
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SK
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
<MenuItem key="sv" value="sv">
|
||||||
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<SVflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
SV
|
SV
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="tr" value="tr">
|
<MenuItem key="tr" value="tr">
|
||||||
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<TRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
TR
|
TR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { jwtDecode } from 'jwt-decode';
|
import jwtDecode from 'jwt-decode';
|
||||||
import { ACCESS_TOKEN, alovaInstance } from './endpoints';
|
import { ACCESS_TOKEN, alovaInstance } from './endpoints';
|
||||||
import type * as H from 'history';
|
import type * as H from 'history';
|
||||||
import type { Path } from 'react-router-dom';
|
import type { Path } from 'react-router-dom';
|
||||||
|
|||||||
@@ -498,8 +498,8 @@ function createStructureReader(structure, firstId) {
|
|||||||
key === '__proto__'
|
key === '__proto__'
|
||||||
? '__proto_:r()'
|
? '__proto_:r()'
|
||||||
: validName.test(key)
|
: validName.test(key)
|
||||||
? key + ':r()'
|
? key + ':r()'
|
||||||
: '[' + JSON.stringify(key) + ']:r()'
|
: '[' + JSON.stringify(key) + ']:r()'
|
||||||
)
|
)
|
||||||
.join(',') +
|
.join(',') +
|
||||||
'})}'
|
'})}'
|
||||||
|
|||||||
@@ -14,20 +14,20 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useState, useContext } from 'react';
|
import { useState, useContext } from 'react';
|
||||||
import type { TypographyProps } from '@mui/material';
|
import type { TypographyProps } from '@mui/material';
|
||||||
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
import type { Locales } from 'i18n/i18n-types';
|
||||||
import type { FC, ChangeEventHandler } from 'react';
|
import type { FC, ChangeEventHandler } from 'react';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import DEflag from 'i18n/DE.svg';
|
|
||||||
import FRflag from 'i18n/FR.svg';
|
|
||||||
import GBflag from 'i18n/GB.svg';
|
|
||||||
import ITflag from 'i18n/IT.svg';
|
|
||||||
import NLflag from 'i18n/NL.svg';
|
|
||||||
import NOflag from 'i18n/NO.svg';
|
|
||||||
import PLflag from 'i18n/PL.svg';
|
|
||||||
import SKflag from 'i18n/SK.svg';
|
|
||||||
import SVflag from 'i18n/SV.svg';
|
|
||||||
import TRflag from 'i18n/TR.svg';
|
|
||||||
|
|
||||||
|
import { ReactComponent as DEflag } from 'i18n/DE.svg';
|
||||||
|
import { ReactComponent as FRflag } from 'i18n/FR.svg';
|
||||||
|
import { ReactComponent as GBflag } from 'i18n/GB.svg';
|
||||||
|
import { ReactComponent as ITflag } from 'i18n/IT.svg';
|
||||||
|
import { ReactComponent as NLflag } from 'i18n/NL.svg';
|
||||||
|
import { ReactComponent as NOflag } from 'i18n/NO.svg';
|
||||||
|
import { ReactComponent as PLflag } from 'i18n/PL.svg';
|
||||||
|
import { ReactComponent as SVflag } from 'i18n/SV.svg';
|
||||||
|
import { ReactComponent as TRflag } from 'i18n/TR.svg';
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
|
|
||||||
@@ -75,43 +75,39 @@ const LayoutAuthMenu: FC = () => {
|
|||||||
select
|
select
|
||||||
>
|
>
|
||||||
<MenuItem key="de" value="de">
|
<MenuItem key="de" value="de">
|
||||||
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<DEflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
DE
|
DE
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="en" value="en">
|
<MenuItem key="en" value="en">
|
||||||
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<GBflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
EN
|
EN
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="fr" value="fr">
|
<MenuItem key="fr" value="fr">
|
||||||
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<FRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
FR
|
FR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="it" value="it">
|
<MenuItem key="it" value="it">
|
||||||
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<ITflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
IT
|
IT
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="nl" value="nl">
|
<MenuItem key="nl" value="nl">
|
||||||
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<NLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NL
|
NL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="no" value="no">
|
<MenuItem key="no" value="no">
|
||||||
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<NOflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NO
|
NO
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="pl" value="pl">
|
<MenuItem key="pl" value="pl">
|
||||||
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<PLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
PL
|
PL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="sk" value="sk">
|
|
||||||
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SK
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
<MenuItem key="sv" value="sv">
|
||||||
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<SVflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
SV
|
SV
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="tr" value="tr">
|
<MenuItem key="tr" value="tr">
|
||||||
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
<TRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
TR
|
TR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const RouterTabs: FC<RouterTabsProps> = ({ value, children }) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
|
const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
const handleTabChange = (_event: any, path: string) => {
|
const handleTabChange = (event: React.ChangeEvent<HTMLInputElement>, path: string) => {
|
||||||
navigate(path);
|
navigate(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { useLocation } from 'react-router-dom';
|
import { useMatch, useResolvedPath } from 'react-router-dom';
|
||||||
|
|
||||||
export const useRouterTab = () => {
|
export const useRouterTab = () => {
|
||||||
const loc = useLocation().pathname;
|
const routerTabPath = useResolvedPath(':tab');
|
||||||
const routerTab = loc.substring(0, loc.lastIndexOf('/')) ? loc : false;
|
const routerTabPathMatch = useMatch(routerTabPath.pathname);
|
||||||
|
|
||||||
// const routerTabPath = useResolvedPath(':tab');
|
|
||||||
// const routerTabPathMatch = useMatch(routerTabPath.pathname);
|
|
||||||
// const routerTab = routerTabPathMatch?.params?.tab || false;
|
|
||||||
|
|
||||||
|
const routerTab = routerTabPathMatch?.params?.tab || false;
|
||||||
return { routerTab } as const;
|
return { routerTab } as const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { redirect } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { AuthenticationContext } from './context';
|
import { AuthenticationContext } from './context';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -15,6 +15,8 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [initialized, setInitialized] = useState<boolean>(false);
|
const [initialized, setInitialized] = useState<boolean>(false);
|
||||||
const [me, setMe] = useState<Me>();
|
const [me, setMe] = useState<Me>();
|
||||||
|
|
||||||
@@ -34,12 +36,11 @@ const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const signOut = (doRedirect: boolean) => {
|
const signOut = (redirect: boolean) => {
|
||||||
AuthenticationApi.clearAccessToken();
|
AuthenticationApi.clearAccessToken();
|
||||||
setMe(undefined);
|
setMe(undefined);
|
||||||
if (doRedirect) {
|
if (redirect) {
|
||||||
// navigate('/');
|
navigate('/');
|
||||||
redirect('/');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,8 @@ const AccessPoint: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/ap/status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
<Tab value="status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
||||||
<Tab
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} disabled={!authenticatedContext.me.admin} />
|
||||||
value="/ap/settings"
|
|
||||||
label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<APStatusForm />} />
|
<Route path="status" element={<APStatusForm />} />
|
||||||
@@ -40,7 +36,7 @@ const AccessPoint: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/ap/status" />} />
|
<Route path="/*" element={<Navigate replace to="status" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const Mqtt: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/mqtt/status" label={LL.STATUS_OF('MQTT')} />
|
<Tab value="status" label={LL.STATUS_OF('MQTT')} />
|
||||||
<Tab value="/mqtt/settings" label={LL.SETTINGS_OF('MQTT')} disabled={!authenticatedContext.me.admin} />
|
<Tab value="settings" label={LL.SETTINGS_OF('MQTT')} disabled={!authenticatedContext.me.admin} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<MqttStatusForm />} />
|
<Route path="status" element={<MqttStatusForm />} />
|
||||||
@@ -34,7 +34,7 @@ const Mqtt: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/mqtt/status" />} />
|
<Route path="/*" element={<Navigate replace to="status" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -168,24 +168,20 @@ const MqttSettingsForm: FC = () => {
|
|||||||
<MenuItem value={2}>2</MenuItem>
|
<MenuItem value={2}>2</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{data.rootCA !== undefined && (
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<ValidatedPasswordField
|
||||||
|
name="rootCA"
|
||||||
|
label={LL.CERT()}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.rootCA}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
{data.enableTLS !== undefined && (
|
|
||||||
<BlockFormControlLabel
|
|
||||||
control={<Checkbox name="enableTLS" checked={data.enableTLS} onChange={updateFormValue} />}
|
|
||||||
label={LL.ENABLE_TLS()}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{data.enableTLS === true && (
|
|
||||||
<ValidatedPasswordField
|
|
||||||
name="rootCA"
|
|
||||||
label={LL.CERT()}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.rootCA}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ const MqttStatusForm: FC = () => {
|
|||||||
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
||||||
return 'Not authorized';
|
return 'Not authorized';
|
||||||
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
||||||
return 'TLS fingerprint invalid';
|
return 'TSL fingerprint invalid';
|
||||||
default:
|
default:
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,13 +44,9 @@ const NetworkConnection: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/network/status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
<Tab value="status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
||||||
<Tab value="/network/scan" label={LL.NETWORK_SCAN()} disabled={!authenticatedContext.me.admin} />
|
<Tab value="scan" label={LL.NETWORK_SCAN()} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} disabled={!authenticatedContext.me.admin} />
|
||||||
value="/network/settings"
|
|
||||||
label={LL.SETTINGS_OF(LL.NETWORK(1))}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NetworkStatusForm />} />
|
<Route path="status" element={<NetworkStatusForm />} />
|
||||||
@@ -70,7 +66,7 @@ const NetworkConnection: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/network/status" />} />
|
<Route path="/*" element={<Navigate replace to="status" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</WiFiConnectionContext.Provider>
|
</WiFiConnectionContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
if (selectedNetwork) {
|
if (selectedNetwork) {
|
||||||
updateState('networkSettings', (current_data) => ({
|
updateState('networkSettings', (current_data) => ({
|
||||||
ssid: selectedNetwork.ssid,
|
ssid: selectedNetwork.ssid,
|
||||||
bssid: selectedNetwork.bssid,
|
password: '',
|
||||||
password: current_data ? current_data.password : '',
|
|
||||||
hostname: current_data?.hostname,
|
hostname: current_data?.hostname,
|
||||||
static_ip_config: false,
|
static_ip_config: false,
|
||||||
enableIPv6: false,
|
enableIPv6: false,
|
||||||
@@ -118,12 +117,6 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
} catch (errors: any) {
|
} catch (errors: any) {
|
||||||
setFieldErrors(errors);
|
setFieldErrors(errors);
|
||||||
}
|
}
|
||||||
deselectNetwork();
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCancel = async () => {
|
|
||||||
deselectNetwork();
|
|
||||||
await loadData();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const restart = async () => {
|
const restart = async () => {
|
||||||
@@ -146,17 +139,10 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={selectedNetwork.ssid}
|
primary={selectedNetwork.ssid}
|
||||||
secondary={
|
secondary={'Security: ' + networkSecurityMode(selectedNetwork) + ', Ch: ' + selectedNetwork.channel}
|
||||||
'Security: ' +
|
|
||||||
networkSecurityMode(selectedNetwork) +
|
|
||||||
', Ch: ' +
|
|
||||||
selectedNetwork.channel +
|
|
||||||
', bssid: ' +
|
|
||||||
selectedNetwork.bssid
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<IconButton onClick={setCancel}>
|
<IconButton onClick={deselectNetwork}>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
@@ -174,16 +160,6 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ValidatedTextField
|
|
||||||
fieldErrors={fieldErrors}
|
|
||||||
name="bssid"
|
|
||||||
label={'BSSID (' + LL.NETWORK_BLANK_BSSID() + ')'}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.bssid}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
@@ -313,14 +289,14 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{restartNeeded && (
|
{restartNeeded && (
|
||||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
|
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
||||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||||
{LL.RESTART()}
|
{LL.RESTART()}
|
||||||
</Button>
|
</Button>
|
||||||
</MessageBox>
|
</MessageBox>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!restartNeeded && (selectedNetwork || (dirtyFlags && dirtyFlags.length !== 0)) && (
|
{!restartNeeded && dirtyFlags && dirtyFlags.length !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
|
|||||||
@@ -38,15 +38,6 @@ const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const networkQualityHighlight = ({ rssi }: NetworkStatus, theme: Theme) => {
|
|
||||||
if (rssi <= -85) {
|
|
||||||
return theme.palette.error.main;
|
|
||||||
} else if (rssi <= -75) {
|
|
||||||
return theme.palette.warning.main;
|
|
||||||
}
|
|
||||||
return theme.palette.success.main;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
|
export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
|
||||||
export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
||||||
|
|
||||||
@@ -119,11 +110,11 @@ const NetworkStatusForm: FC = () => {
|
|||||||
<>
|
<>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar sx={{ bgcolor: networkQualityHighlight(data, theme) }}>
|
<Avatar>
|
||||||
<SettingsInputAntennaIcon />
|
<SettingsInputAntennaIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText primary="SSID (RSSI)" secondary={data.ssid + ' (' + data.rssi + ' dBm)'} />
|
<ListItemText primary="SSID" secondary={data.ssid} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
import LockOpenIcon from '@mui/icons-material/LockOpen';
|
import LockOpenIcon from '@mui/icons-material/LockOpen';
|
||||||
import WifiIcon from '@mui/icons-material/Wifi';
|
import WifiIcon from '@mui/icons-material/Wifi';
|
||||||
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText, useTheme } from '@mui/material';
|
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
||||||
import type { Theme } from '@mui/material';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import type { WiFiNetwork, WiFiNetworkList } from 'types';
|
import type { WiFiNetwork, WiFiNetworkList } from 'types';
|
||||||
import { MessageBox } from 'components';
|
import { MessageBox } from 'components';
|
||||||
@@ -43,18 +42,8 @@ export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const networkQualityHighlight = ({ rssi }: WiFiNetwork, theme: Theme) => {
|
|
||||||
if (rssi <= -85) {
|
|
||||||
return theme.palette.error.main;
|
|
||||||
} else if (rssi <= -75) {
|
|
||||||
return theme.palette.warning.main;
|
|
||||||
}
|
|
||||||
return theme.palette.success.main;
|
|
||||||
};
|
|
||||||
|
|
||||||
const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const wifiConnectionContext = useContext(WiFiConnectionContext);
|
const wifiConnectionContext = useContext(WiFiConnectionContext);
|
||||||
|
|
||||||
@@ -65,13 +54,11 @@ const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={network.ssid}
|
primary={network.ssid}
|
||||||
secondary={
|
secondary={'Security: ' + networkSecurityMode(network) + ', Ch: ' + network.channel}
|
||||||
'Security: ' + networkSecurityMode(network) + ', Ch: ' + network.channel + ', bssid: ' + network.bssid
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Badge badgeContent={network.rssi + 'dBm'}>
|
<Badge badgeContent={network.rssi + 'db'}>
|
||||||
<WifiIcon sx={{ color: networkQualityHighlight(network, theme) }} />
|
<WifiIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ const NetworkTime: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/ntp/status" label={LL.STATUS_OF('NTP')} />
|
<Tab value="status" label={LL.STATUS_OF('NTP')} />
|
||||||
<Tab value="/ntp/settings" label={LL.SETTINGS_OF('NTP')} disabled={!authenticatedContext.me.admin} />
|
<Tab value="settings" label={LL.SETTINGS_OF('NTP')} disabled={!authenticatedContext.me.admin} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NTPStatusForm />} />
|
<Route path="status" element={<NTPStatusForm />} />
|
||||||
@@ -33,7 +33,7 @@ const NetworkTime: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/ntp/status" />} />
|
<Route path="/*" element={<Navigate replace to="status" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-li
|
|||||||
import { useTheme } from '@table-library/react-table-library/theme';
|
import { useTheme } from '@table-library/react-table-library/theme';
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
|
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
import GenerateToken from './GenerateToken';
|
import GenerateToken from './GenerateToken';
|
||||||
import UserForm from './UserForm';
|
import UserForm from './UserForm';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ const Security: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/security/users" label={LL.MANAGE_USERS()} />
|
<Tab value="users" label={LL.MANAGE_USERS()} />
|
||||||
<Tab value="/security/settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="users" element={<ManageUsersForm />} />
|
<Route path="users" element={<ManageUsersForm />} />
|
||||||
<Route path="settings" element={<SecuritySettingsForm />} />
|
<Route path="settings" element={<SecuritySettingsForm />} />
|
||||||
<Route path="*" element={<Navigate replace to="/security/users" />} />
|
<Route path="/*" element={<Navigate replace to="users" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ const System: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/system/status" label={LL.STATUS_OF(LL.SYSTEM(1))} />
|
<Tab value="status" label={LL.STATUS_OF(LL.SYSTEM(1))} />
|
||||||
<Tab value="/system/log" label={LL.LOG_OF(LL.SYSTEM(2))} />
|
<Tab value="log" label={LL.LOG_OF(LL.SYSTEM(2))} />
|
||||||
<Tab value="/system/ota" label={LL.SETTINGS_OF('OTA')} disabled={!me.admin} />
|
<Tab value="ota" label={LL.SETTINGS_OF('OTA')} disabled={!me.admin} />
|
||||||
<Tab value="/system/upload" label={LL.UPLOAD_DOWNLOAD()} disabled={!me.admin} />
|
<Tab value="upload" label={LL.UPLOAD_DOWNLOAD()} disabled={!me.admin} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<SystemStatusForm />} />
|
<Route path="status" element={<SystemStatusForm />} />
|
||||||
@@ -47,7 +47,7 @@ const System: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/system/status" />} />
|
<Route path="/*" element={<Navigate replace to="status" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import AppsIcon from '@mui/icons-material/Apps';
|
import AppsIcon from '@mui/icons-material/Apps';
|
||||||
import BuildIcon from '@mui/icons-material/Build';
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import DeveloperBoardIcon from '@mui/icons-material/DeveloperBoard';
|
|
||||||
import DevicesIcon from '@mui/icons-material/Devices';
|
import DevicesIcon from '@mui/icons-material/Devices';
|
||||||
import FolderIcon from '@mui/icons-material/Folder';
|
import FolderIcon from '@mui/icons-material/Folder';
|
||||||
import MemoryIcon from '@mui/icons-material/Memory';
|
import MemoryIcon from '@mui/icons-material/Memory';
|
||||||
@@ -10,6 +9,7 @@ import RefreshIcon from '@mui/icons-material/Refresh';
|
|||||||
import SdCardAlertIcon from '@mui/icons-material/SdCardAlert';
|
import SdCardAlertIcon from '@mui/icons-material/SdCardAlert';
|
||||||
import SdStorageIcon from '@mui/icons-material/SdStorage';
|
import SdStorageIcon from '@mui/icons-material/SdStorage';
|
||||||
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
|
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
|
||||||
|
import ShowChartIcon from '@mui/icons-material/ShowChart';
|
||||||
import TimerIcon from '@mui/icons-material/Timer';
|
import TimerIcon from '@mui/icons-material/Timer';
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
@@ -200,6 +200,15 @@ const SystemStatusForm: FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar>
|
||||||
|
<DevicesIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.PLATFORM()} secondary={data.esp_platform + ' / ' + data.sdk_version} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar>
|
<Avatar>
|
||||||
@@ -212,31 +221,10 @@ const SystemStatusForm: FC = () => {
|
|||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar>
|
<Avatar>
|
||||||
<DevicesIcon />
|
<ShowChartIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText primary="SDK" secondary={data.arduino_version + ' / ESP-IDF v' + data.sdk_version} />
|
<ListItemText primary={LL.CPU_FREQ()} secondary={data.cpu_freq_mhz + ' MHz'} />
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<DeveloperBoardIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary="CPU"
|
|
||||||
secondary={
|
|
||||||
data.cpu_type +
|
|
||||||
' (rev.' +
|
|
||||||
data.cpu_rev +
|
|
||||||
', ' +
|
|
||||||
(data.cpu_cores == 1 ? 'single-core)' : 'dual-core)') +
|
|
||||||
' @ ' +
|
|
||||||
data.cpu_freq_mhz +
|
|
||||||
' Mhz'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
<ListItem>
|
<ListItem>
|
||||||
@@ -289,9 +277,7 @@ const SystemStatusForm: FC = () => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.APPSIZE()}
|
primary={LL.APPSIZE()}
|
||||||
secondary={
|
secondary={formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'}
|
||||||
data.partition + ': ' + formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import * as EMSESP from 'project/api';
|
|||||||
|
|
||||||
const UploadFileForm: FC = () => {
|
const UploadFileForm: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [restarting, setRestarting] = useState<boolean>();
|
const [restarting, setRestarting] = useState<boolean>(false);
|
||||||
const [md5, setMd5] = useState<string>();
|
const [md5, setMd5] = useState<string>();
|
||||||
|
|
||||||
const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), {
|
const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), {
|
||||||
@@ -28,9 +28,6 @@ const UploadFileForm: FC = () => {
|
|||||||
const { send: getSchedule, onSuccess: onSuccessGetSchedule } = useRequest(EMSESP.getSchedule(), {
|
const { send: getSchedule, onSuccess: onSuccessGetSchedule } = useRequest(EMSESP.getSchedule(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
const { send: getSystemAPI, onSuccess: onSystemAPI } = useRequest((data) => EMSESP.APIcall('system', data), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loading: isUploading,
|
loading: isUploading,
|
||||||
@@ -71,26 +68,23 @@ const UploadFileForm: FC = () => {
|
|||||||
type: 'text/plain'
|
type: 'text/plain'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
anchor.download = 'emsesp_' + endpoint;
|
anchor.download = 'emsesp_' + endpoint + '.json';
|
||||||
anchor.click();
|
anchor.click();
|
||||||
URL.revokeObjectURL(anchor.href);
|
URL.revokeObjectURL(anchor.href);
|
||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
};
|
};
|
||||||
|
|
||||||
onSuccessGetSettings((event) => {
|
onSuccessGetSettings((event) => {
|
||||||
saveFile(event.data, 'settings.json');
|
saveFile(event.data, 'settings');
|
||||||
});
|
});
|
||||||
onSuccessgetCustomizations((event) => {
|
onSuccessgetCustomizations((event) => {
|
||||||
saveFile(event.data, 'customizations.json');
|
saveFile(event.data, 'customizations');
|
||||||
});
|
});
|
||||||
onSuccessGetEntities((event) => {
|
onSuccessGetEntities((event) => {
|
||||||
saveFile(event.data, 'entities.json');
|
saveFile(event.data, 'entities');
|
||||||
});
|
});
|
||||||
onSuccessGetSchedule((event) => {
|
onSuccessGetSchedule((event) => {
|
||||||
saveFile(event.data, 'schedule.json');
|
saveFile(event.data, 'schedule');
|
||||||
});
|
|
||||||
onSystemAPI((event) => {
|
|
||||||
saveFile(event.data, event.sendArgs[0].entity + '.txt');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const downloadSettings = async () => {
|
const downloadSettings = async () => {
|
||||||
@@ -112,17 +106,7 @@ const UploadFileForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const downloadSchedule = async () => {
|
const downloadSchedule = async () => {
|
||||||
await getSchedule()
|
await getSchedule().catch((error) => {
|
||||||
.catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const callSystemAPI = async (entity: string) => {
|
|
||||||
await getSystemAPI({ entity, id: 0 }).catch((error) => {
|
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -133,12 +117,7 @@ const UploadFileForm: FC = () => {
|
|||||||
{LL.UPLOAD()}
|
{LL.UPLOAD()}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">{LL.UPLOAD_TEXT()} </Typography>
|
||||||
{LL.UPLOAD_TEXT()}.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
{LL.RESTART_TEXT(1)}.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
{md5 && (
|
{md5 && (
|
||||||
<Box mb={2}>
|
<Box mb={2}>
|
||||||
@@ -148,29 +127,8 @@ const UploadFileForm: FC = () => {
|
|||||||
<SingleUpload onDrop={startUpload} onCancel={cancelUpload} isUploading={isUploading} progress={progress} />
|
<SingleUpload onDrop={startUpload} onCancel={cancelUpload} isUploading={isUploading} progress={progress} />
|
||||||
{!isUploading && (
|
{!isUploading && (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
{LL.DOWNLOAD(0)} {LL.SUPPORT_INFORMATION(1)}
|
{LL.DOWNLOAD(0)}
|
||||||
</Typography>
|
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography mb={1} variant="body2">
|
|
||||||
{LL.HELP_INFORMATION_4()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callSystemAPI('info')}>
|
|
||||||
{LL.SUPPORT_INFORMATION(0)}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
sx={{ ml: 2 }}
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => callSystemAPI('allvalues')}
|
|
||||||
>
|
|
||||||
All Values
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
|
|
||||||
{LL.DOWNLOAD(0)} {LL.SETTINGS(1)}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box color="warning.main">
|
<Box color="warning.main">
|
||||||
<Typography mb={1} variant="body2">
|
<Typography mb={1} variant="body2">
|
||||||
@@ -182,7 +140,7 @@ const UploadFileForm: FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Box color="warning.main">
|
<Box color="warning.main">
|
||||||
<Typography mt={2} mb={1} variant="body2">
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}
|
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}{' '}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadCustomizations}>
|
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadCustomizations}>
|
||||||
@@ -199,7 +157,7 @@ const UploadFileForm: FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Box color="warning.main">
|
<Box color="warning.main">
|
||||||
<Typography mt={2} mb={1} variant="body2">
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
{LL.DOWNLOAD_SCHEDULE_TEXT()}
|
{LL.DOWNLOAD_SCHEDULE_TEXT()}{' '}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSchedule}>
|
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSchedule}>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 85.333 512 341.333"><path fill="#FFF" d="M0 85.337h512v341.326H0z"/><path fill="#0052B4" d="M0 196.641h512v118.717H0z"/><path fill="#D80027" d="M0 315.359h512v111.304H0z"/><path fill="#FFF" d="M129.468 181.799v85.136c0 48.429 63.267 63.267 63.267 63.267S256 315.362 256 266.935v-85.136H129.468z"/><path fill="#D80027" d="M146.126 184.294v81.941c0 5.472 1.215 10.64 3.623 15.485h85.97c2.408-4.844 3.623-10.012 3.623-15.485v-81.941h-93.216z"/><path fill="#FFF" d="M221.301 241.427h-21.425v-14.283h14.284v-14.283h-14.284v-14.284h-14.283v14.284h-14.282v14.283h14.282v14.283h-21.426v14.284h21.426v14.283h14.283v-14.283h21.425z"/><path fill="#0052B4" d="M169.232 301.658c9.204 5.783 18.66 9.143 23.502 10.636 4.842-1.494 14.298-4.852 23.502-10.636 9.282-5.833 15.79-12.506 19.484-19.939a24.878 24.878 0 0 0-14.418-4.583c-1.956 0-3.856.232-5.682.657-3.871-8.796-12.658-14.94-22.884-14.94-10.227 0-19.013 6.144-22.884 14.94a25.048 25.048 0 0 0-5.682-.657 24.88 24.88 0 0 0-14.418 4.583c3.691 7.433 10.198 14.106 19.48 19.939z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -126,7 +126,6 @@ const de: Translation = {
|
|||||||
BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen',
|
BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen',
|
||||||
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
|
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
|
||||||
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
|
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
|
||||||
HEATINGOFF: 'Heizen ausschalten beim EMS-ESP Start',
|
|
||||||
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',
|
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',
|
||||||
ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren',
|
ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren',
|
||||||
TRIGGER_TIME: 'Auslösezeit',
|
TRIGGER_TIME: 'Auslösezeit',
|
||||||
@@ -171,6 +170,7 @@ const de: Translation = {
|
|||||||
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 System-Details und hängen Sie sie an das Support-Issue an. ',
|
HELP_INFORMATION_4: 'Bitte laden Sie die System-Details und hängen Sie sie an das Support-Issue an. ',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP ist ein freies Open-Source Projekt. Bitte unterstützen Sie die zukünftige Entwicklung mit einem "Star" auf Github!',
|
HELP_INFORMATION_5: 'EMS-ESP ist ein freies Open-Source Projekt. Bitte unterstützen Sie die zukünftige Entwicklung mit einem "Star" auf Github!',
|
||||||
|
SUPPORT_INFO: 'Support Info',
|
||||||
UPLOAD: 'Hochladen',
|
UPLOAD: 'Hochladen',
|
||||||
DOWNLOAD: '{{H|h|h}}erunterladen',
|
DOWNLOAD: '{{H|h|h}}erunterladen',
|
||||||
ABORTED: 'abgebrochen',
|
ABORTED: 'abgebrochen',
|
||||||
@@ -194,11 +194,13 @@ const de: Translation = {
|
|||||||
RELEASE_IS: 'release ist', // TODO translate
|
RELEASE_IS: 'release ist', // TODO translate
|
||||||
RELEASE_NOTES: 'Versionshinweise',
|
RELEASE_NOTES: 'Versionshinweise',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
|
PLATFORM: 'Platform (Platform / SDK)',
|
||||||
UPTIME: 'System Betriebszeit',
|
UPTIME: 'System Betriebszeit',
|
||||||
|
CPU_FREQ: 'CPU Frequenz',
|
||||||
HEAP: 'freier RAM Speicher (Gesamt / max. Block)',
|
HEAP: 'freier RAM Speicher (Gesamt / max. Block)',
|
||||||
PSRAM: 'PSRAM (Größe / Frei)',
|
PSRAM: 'PSRAM (Größe / Frei)',
|
||||||
FLASH: 'Flash Speicher (Größe / Geschwindigkeit)',
|
FLASH: 'Flash Speicher (Größe / Geschwindigkeit)',
|
||||||
APPSIZE: 'Programm (Partition: Genutzt / Frei)',
|
APPSIZE: 'Programm (Genutzt / Frei)',
|
||||||
FILESYSTEM: 'Dateisystem (Genutzt / Frei)',
|
FILESYSTEM: 'Dateisystem (Genutzt / Frei)',
|
||||||
BUFFER_SIZE: 'max. Puffergröße',
|
BUFFER_SIZE: 'max. Puffergröße',
|
||||||
COMPACT: 'Kompakte Darstellung',
|
COMPACT: 'Kompakte Darstellung',
|
||||||
@@ -228,7 +230,7 @@ const de: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Optional', // TODO translate
|
OPTIONAL: 'Optional',
|
||||||
FORMATTING: 'Formattierung',
|
FORMATTING: 'Formattierung',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Eingebettet in einem Gesamttopic',
|
MQTT_NEST_1: 'Eingebettet in einem Gesamttopic',
|
||||||
@@ -280,7 +282,6 @@ const de: Translation = {
|
|||||||
NETWORK_SCANNER: 'Netzwerk Suche',
|
NETWORK_SCANNER: 'Netzwerk Suche',
|
||||||
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
||||||
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren',
|
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren',
|
||||||
NETWORK_BLANK_BSSID: 'Freilassen um nur SSID für die Verbindung zu nutzen',
|
|
||||||
TX_POWER: 'Tx Leistung',
|
TX_POWER: 'Tx Leistung',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
||||||
@@ -321,15 +322,7 @@ const de: Translation = {
|
|||||||
WRITEABLE: 'Schreibbar',
|
WRITEABLE: 'Schreibbar',
|
||||||
SHOWING: 'Anzeigen von',
|
SHOWING: 'Anzeigen von',
|
||||||
SEARCH: 'Suche',
|
SEARCH: 'Suche',
|
||||||
CERT: 'TLS Zertifikat (Freilassen für unsichere Verbindung)',
|
CERT: 'TSL Zertifikat (Freilassen um TSL zu deaktivieren)'
|
||||||
ENABLE_TLS: 'Aktiviere TLS',
|
|
||||||
ON: 'An',
|
|
||||||
OFF: 'Aus',
|
|
||||||
POLARITY: 'Polarität',
|
|
||||||
ACTIVEHIGH: 'Aktiv Positiv',
|
|
||||||
ACTIVELOW: 'Aktiv Negativ',
|
|
||||||
UNCHANGED: 'Unverändert',
|
|
||||||
ALWAYS: 'Immer'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ const en: Translation = {
|
|||||||
BYPASS_TOKEN: 'Bypass Access Token authorization on API calls',
|
BYPASS_TOKEN: 'Bypass Access Token authorization on API calls',
|
||||||
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
|
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
|
||||||
UNDERCLOCK_CPU: 'Underclock CPU speed',
|
UNDERCLOCK_CPU: 'Underclock CPU speed',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off',
|
|
||||||
ENABLE_SHOWER_TIMER: 'Enable Shower Timer',
|
ENABLE_SHOWER_TIMER: 'Enable Shower Timer',
|
||||||
ENABLE_SHOWER_ALERT: 'Enable Shower Alert',
|
ENABLE_SHOWER_ALERT: 'Enable Shower Alert',
|
||||||
TRIGGER_TIME: 'Trigger Time',
|
TRIGGER_TIME: 'Trigger Time',
|
||||||
@@ -169,8 +168,9 @@ const en: Translation = {
|
|||||||
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
||||||
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: 'Remember to download and attach your support information for a faster response when reporting an issue',
|
HELP_INFORMATION_4: 'remember to download and attach your system information for a faster response when reporting an issue',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!',
|
HELP_INFORMATION_5: 'EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!',
|
||||||
|
SUPPORT_INFO: 'Support Info',
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'aborted',
|
ABORTED: 'aborted',
|
||||||
@@ -196,10 +196,11 @@ const en: Translation = {
|
|||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
PLATFORM: 'Device (Platform / SDK)',
|
PLATFORM: 'Device (Platform / SDK)',
|
||||||
UPTIME: 'System Uptime',
|
UPTIME: 'System Uptime',
|
||||||
|
CPU_FREQ: 'CPU Frequency',
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Application (Partition: Used / Free)',
|
APPSIZE: 'Application (Used / Free)',
|
||||||
FILESYSTEM: 'File System (Used / Free)',
|
FILESYSTEM: 'File System (Used / Free)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -229,7 +230,7 @@ const en: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'optional',
|
OPTIONAL: 'Optional',
|
||||||
FORMATTING: 'Formatting',
|
FORMATTING: 'Formatting',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nested in a single topic',
|
MQTT_NEST_1: 'Nested in a single topic',
|
||||||
@@ -281,7 +282,6 @@ const en: Translation = {
|
|||||||
NETWORK_SCANNER: 'Network Scanner',
|
NETWORK_SCANNER: 'Network Scanner',
|
||||||
NETWORK_NO_WIFI: 'No WiFi networks found',
|
NETWORK_NO_WIFI: 'No WiFi networks found',
|
||||||
NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH',
|
NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID',
|
|
||||||
TX_POWER: 'Tx Power',
|
TX_POWER: 'Tx Power',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
||||||
@@ -322,15 +322,7 @@ const en: Translation = {
|
|||||||
WRITEABLE: 'Writeable',
|
WRITEABLE: 'Writeable',
|
||||||
SHOWING: 'Showing',
|
SHOWING: 'Showing',
|
||||||
SEARCH: 'Search',
|
SEARCH: 'Search',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)',
|
CERT: 'TSL root certificate (leave blank to disable TSL)'
|
||||||
ENABLE_TLS: 'Enable TLS',
|
|
||||||
ON: 'On',
|
|
||||||
OFF: 'Off',
|
|
||||||
POLARITY: 'Polarity',
|
|
||||||
ACTIVEHIGH: 'Active High',
|
|
||||||
ACTIVELOW: 'Active Low',
|
|
||||||
UNCHANGED: 'Unchanged',
|
|
||||||
ALWAYS: 'Always'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ const fr: Translation = {
|
|||||||
BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API',
|
BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API',
|
||||||
READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)',
|
READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)',
|
||||||
UNDERCLOCK_CPU: 'Underclock du CPU',
|
UNDERCLOCK_CPU: 'Underclock du CPU',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
|
||||||
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
|
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
|
||||||
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
|
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
|
||||||
TRIGGER_TIME: 'Durée avant déclenchement',
|
TRIGGER_TIME: 'Durée avant déclenchement',
|
||||||
@@ -169,8 +168,9 @@ const fr: Translation = {
|
|||||||
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
||||||
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: 'EMS-ESP est un projet libre et open-source. Merci de soutenir son développement futur en lui donnant une étoile sur Github !',
|
HELP_INFORMATION_5: 'EMS-ESP est un projet libre et open-source. Merci de soutenir son développement futur en lui donnant une étoile sur Github !',
|
||||||
|
SUPPORT_INFO: 'Information de support',
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'annulé',
|
ABORTED: 'annulé',
|
||||||
@@ -194,11 +194,13 @@ const fr: Translation = {
|
|||||||
RELEASE_IS: 'release est', // TODO translate
|
RELEASE_IS: 'release est', // TODO translate
|
||||||
RELEASE_NOTES: 'notes de version',
|
RELEASE_NOTES: 'notes de version',
|
||||||
EMS_ESP_VER: 'Version EMS-ESP',
|
EMS_ESP_VER: 'Version EMS-ESP',
|
||||||
|
PLATFORM: 'Appareil (Plateforme / SDK)',
|
||||||
UPTIME: 'Durée de fonctionnement du système',
|
UPTIME: 'Durée de fonctionnement du système',
|
||||||
|
CPU_FREQ: 'Fréquence du CPU',
|
||||||
HEAP: 'Heap (Libre / Max Allouée)',
|
HEAP: 'Heap (Libre / Max Allouée)',
|
||||||
PSRAM: 'PSRAM (Taille / Libre)',
|
PSRAM: 'PSRAM (Taille / Libre)',
|
||||||
FLASH: 'Flash Chip (Taille / Vitesse)',
|
FLASH: 'Flash Chip (Taille / Vitesse)',
|
||||||
APPSIZE: 'Application (Partition: Utilisée / Libre)',
|
APPSIZE: 'Application (Utilisée / Libre)',
|
||||||
FILESYSTEM: 'File System (Utilisée / Libre)',
|
FILESYSTEM: 'File System (Utilisée / Libre)',
|
||||||
BUFFER_SIZE: 'Max taille du buffer',
|
BUFFER_SIZE: 'Max taille du buffer',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -228,7 +230,7 @@ const fr: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'optionnel',
|
OPTIONAL: 'Optionnel',
|
||||||
FORMATTING: 'Mise en forme',
|
FORMATTING: 'Mise en forme',
|
||||||
MQTT_FORMAT: 'Format du Topic/Payload',
|
MQTT_FORMAT: 'Format du Topic/Payload',
|
||||||
MQTT_NEST_1: 'Englobé dans un topic unique',
|
MQTT_NEST_1: 'Englobé dans un topic unique',
|
||||||
@@ -280,7 +282,6 @@ const fr: Translation = {
|
|||||||
NETWORK_SCANNER: 'Scan réseau',
|
NETWORK_SCANNER: 'Scan réseau',
|
||||||
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
||||||
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate
|
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Puissance Tx',
|
TX_POWER: 'Puissance Tx',
|
||||||
HOSTNAME: 'Nom d\'hôte',
|
HOSTNAME: 'Nom d\'hôte',
|
||||||
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
||||||
@@ -321,15 +322,7 @@ const fr: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'Activer TLS',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ const it: Translation = {
|
|||||||
BYPASS_TOKEN: 'Ignora autorizzazione del token di accesso sulle chiamate API',
|
BYPASS_TOKEN: 'Ignora autorizzazione del token di accesso sulle chiamate API',
|
||||||
READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)',
|
READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)',
|
||||||
UNDERCLOCK_CPU: 'Abbassa velocità della CPU',
|
UNDERCLOCK_CPU: 'Abbassa velocità della CPU',
|
||||||
HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento',
|
|
||||||
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
||||||
ENABLE_SHOWER_ALERT: 'Abilita avviso doccia',
|
ENABLE_SHOWER_ALERT: 'Abilita avviso doccia',
|
||||||
TRIGGER_TIME: 'Tempo di avvio',
|
TRIGGER_TIME: 'Tempo di avvio',
|
||||||
@@ -171,8 +170,9 @@ const it: Translation = {
|
|||||||
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
||||||
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: 'EMS-ESP è un progetto gratuito e open-source. Supporta il suo sviluppo futuro assegnandogli una stella su Github!',
|
HELP_INFORMATION_5: 'EMS-ESP è un progetto gratuito e open-source. Supporta il suo sviluppo futuro assegnandogli una stella su Github!',
|
||||||
|
SUPPORT_INFO: 'Info Supporto',
|
||||||
UPLOAD: 'Carica',
|
UPLOAD: 'Carica',
|
||||||
DOWNLOAD: 'Scarica',
|
DOWNLOAD: 'Scarica',
|
||||||
ABORTED: 'Annullato',
|
ABORTED: 'Annullato',
|
||||||
@@ -196,11 +196,13 @@ const it: Translation = {
|
|||||||
RELEASE_IS: 'rilascio é',
|
RELEASE_IS: 'rilascio é',
|
||||||
RELEASE_NOTES: 'note rilascio',
|
RELEASE_NOTES: 'note rilascio',
|
||||||
EMS_ESP_VER: 'Versione EMS-ESP',
|
EMS_ESP_VER: 'Versione EMS-ESP',
|
||||||
|
PLATFORM: 'Dispositivo (Piattaforma / SDK)',
|
||||||
UPTIME: 'Tempo di attività del sistema',
|
UPTIME: 'Tempo di attività del sistema',
|
||||||
|
CPU_FREQ: 'Frequenza CPU ',
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Applicazione (Partizione: Usata / Libera)',
|
APPSIZE: 'Applicazione (Usata / Libera)',
|
||||||
FILESYSTEM: 'Memoria Sistema (Usata / Libera)',
|
FILESYSTEM: 'Memoria Sistema (Usata / Libera)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -230,7 +232,7 @@ const it: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Cliente',
|
CLIENT: 'Cliente',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'opzionale',
|
OPTIONAL: 'Opzionale',
|
||||||
FORMATTING: 'Formattazione',
|
FORMATTING: 'Formattazione',
|
||||||
MQTT_FORMAT: 'Formato Topic/Payload ',
|
MQTT_FORMAT: 'Formato Topic/Payload ',
|
||||||
MQTT_NEST_1: 'Inserito in un singolo argomento',
|
MQTT_NEST_1: 'Inserito in un singolo argomento',
|
||||||
@@ -282,7 +284,6 @@ const it: Translation = {
|
|||||||
NETWORK_SCANNER: 'Scansione Rete',
|
NETWORK_SCANNER: 'Scansione Rete',
|
||||||
NETWORK_NO_WIFI: 'Nessuana rete WiFi trovata',
|
NETWORK_NO_WIFI: 'Nessuana rete WiFi trovata',
|
||||||
NETWORK_BLANK_SSID: 'lasciare vuoto per disattivare WiFi',
|
NETWORK_BLANK_SSID: 'lasciare vuoto per disattivare WiFi',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Potenza Tx',
|
TX_POWER: 'Potenza Tx',
|
||||||
HOSTNAME: 'Nome ospite',
|
HOSTNAME: 'Nome ospite',
|
||||||
NETWORK_DISABLE_SLEEP: 'Disabilita la modalità sospensione Wi-Fi',
|
NETWORK_DISABLE_SLEEP: 'Disabilita la modalità sospensione Wi-Fi',
|
||||||
@@ -323,15 +324,7 @@ const it: Translation = {
|
|||||||
WRITEABLE: 'Scrivibile',
|
WRITEABLE: 'Scrivibile',
|
||||||
SHOWING: 'Visualizza',
|
SHOWING: 'Visualizza',
|
||||||
SEARCH: 'Ricerca',
|
SEARCH: 'Ricerca',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'Abilita TLS',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ const nl: Translation = {
|
|||||||
BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen',
|
BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen',
|
||||||
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
|
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
|
||||||
UNDERCLOCK_CPU: 'Underclock CPU snelheid',
|
UNDERCLOCK_CPU: 'Underclock CPU snelheid',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
|
||||||
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
||||||
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
||||||
TRIGGER_TIME: 'Trigger tijd',
|
TRIGGER_TIME: 'Trigger tijd',
|
||||||
@@ -169,8 +168,9 @@ const nl: Translation = {
|
|||||||
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
||||||
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: 'EMS-ESP is een gratis en open source project. Steun ons met een Star op Github!',
|
HELP_INFORMATION_5: 'EMS-ESP is een gratis en open source project. Steun ons met een Star op Github!',
|
||||||
|
SUPPORT_INFO: 'Support Info',
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'afgebroken',
|
ABORTED: 'afgebroken',
|
||||||
@@ -194,11 +194,13 @@ const nl: Translation = {
|
|||||||
RELEASE_IS: 'release is',
|
RELEASE_IS: 'release is',
|
||||||
RELEASE_NOTES: 'release notes',
|
RELEASE_NOTES: 'release notes',
|
||||||
EMS_ESP_VER: 'EMS-ESP Versie',
|
EMS_ESP_VER: 'EMS-ESP Versie',
|
||||||
|
PLATFORM: 'Apparaat (Platform / SDK)',
|
||||||
UPTIME: 'Systeem Uptime',
|
UPTIME: 'Systeem Uptime',
|
||||||
|
CPU_FREQ: 'CPU Frequency',
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Application (Partition: Used / Free)',
|
APPSIZE: 'Application (Used / Free)',
|
||||||
FILESYSTEM: 'File System (Used / Free)',
|
FILESYSTEM: 'File System (Used / Free)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -228,7 +230,7 @@ const nl: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'optioneel',
|
OPTIONAL: 'Optioneel',
|
||||||
FORMATTING: 'Formatteren',
|
FORMATTING: 'Formatteren',
|
||||||
MQTT_FORMAT: 'Topic/Payload Formattering',
|
MQTT_FORMAT: 'Topic/Payload Formattering',
|
||||||
MQTT_NEST_1: 'Genest in 1 topic',
|
MQTT_NEST_1: 'Genest in 1 topic',
|
||||||
@@ -280,7 +282,6 @@ const nl: Translation = {
|
|||||||
NETWORK_SCANNER: 'Netwerk Scanner',
|
NETWORK_SCANNER: 'Netwerk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
||||||
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen',
|
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Tx Vermogen',
|
TX_POWER: 'Tx Vermogen',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
||||||
@@ -321,15 +322,7 @@ const nl: Translation = {
|
|||||||
WRITEABLE: 'Beschrijfbare',
|
WRITEABLE: 'Beschrijfbare',
|
||||||
SHOWING: 'Tonen',
|
SHOWING: 'Tonen',
|
||||||
SEARCH: 'Zoek',
|
SEARCH: 'Zoek',
|
||||||
CERT: 'TLS rootcertificaat (laat leeg om TLS-insecure)', // TODO translate
|
CERT: 'TSL rootcertificaat (laat leeg om TSL uit te schakelen)'
|
||||||
ENABLE_TLS: 'Activeer TLS',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ const no: Translation = {
|
|||||||
BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall',
|
BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall',
|
||||||
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
|
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
|
||||||
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
|
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
|
||||||
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer',
|
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling',
|
ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling',
|
||||||
TRIGGER_TIME: 'Aktiveringstid',
|
TRIGGER_TIME: 'Aktiveringstid',
|
||||||
@@ -169,8 +168,9 @@ const no: Translation = {
|
|||||||
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
||||||
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: 'EMS-ESP er gratis og åpen kildekode. Bidra til utviklingen ved å gi oss en stjerne på GitHub!',
|
HELP_INFORMATION_5: 'EMS-ESP er gratis og åpen kildekode. Bidra til utviklingen ved å gi oss en stjerne på GitHub!',
|
||||||
|
SUPPORT_INFO: 'Supportinfo',
|
||||||
UPLOAD: 'Opplasning',
|
UPLOAD: 'Opplasning',
|
||||||
DOWNLOAD: '{{N|n|n}}edlasting',
|
DOWNLOAD: '{{N|n|n}}edlasting',
|
||||||
ABORTED: 'avbrutt',
|
ABORTED: 'avbrutt',
|
||||||
@@ -194,11 +194,13 @@ const no: Translation = {
|
|||||||
RELEASE_IS: 'release er',
|
RELEASE_IS: 'release er',
|
||||||
RELEASE_NOTES: 'release notes',
|
RELEASE_NOTES: 'release notes',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
|
PLATFORM: 'Enhet (Platform / SDK)',
|
||||||
UPTIME: 'System Oppetid',
|
UPTIME: 'System Oppetid',
|
||||||
|
CPU_FREQ: 'CPU Frekvens',
|
||||||
HEAP: 'Heap (Ledig / Max Allokert)',
|
HEAP: 'Heap (Ledig / Max Allokert)',
|
||||||
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
||||||
FLASH: 'Flash Chip (Størrelse / Hastighet)',
|
FLASH: 'Flash Chip (Størrelse / Hastighet)',
|
||||||
APPSIZE: 'Applikasjon (Partition: Brukt / Ledig)',
|
APPSIZE: 'Applikasjon (Brukt / Ledig)',
|
||||||
FILESYSTEM: 'File System (Brukt / Ledig)',
|
FILESYSTEM: 'File System (Brukt / Ledig)',
|
||||||
BUFFER_SIZE: 'Max Buffer Størrelse',
|
BUFFER_SIZE: 'Max Buffer Størrelse',
|
||||||
COMPACT: 'Komprimere',
|
COMPACT: 'Komprimere',
|
||||||
@@ -228,7 +230,7 @@ const no: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'valgfritt',
|
OPTIONAL: 'Valgfritt',
|
||||||
FORMATTING: 'Formatering',
|
FORMATTING: 'Formatering',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nestet i en topic',
|
MQTT_NEST_1: 'Nestet i en topic',
|
||||||
@@ -280,7 +282,6 @@ const no: Translation = {
|
|||||||
NETWORK_SCANNER: 'Nettverk Scanner',
|
NETWORK_SCANNER: 'Nettverk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
||||||
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // TODO translate
|
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // TODO translate
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
||||||
@@ -321,15 +322,7 @@ const no: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'Aktiviser TLS',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const pl: BaseTranslation = {
|
|||||||
PROBLEM_LOADING: 'Problem z załadowaniem!',
|
PROBLEM_LOADING: 'Problem z załadowaniem!',
|
||||||
ANALOG_SENSOR: '{{u|u||ustawienia u|ustawień u}}rządzeni{{a podłączonego do EMS-ESP|e||a podłączonego do EMS-ESP|a podłączonego do EMS-ESP}}',
|
ANALOG_SENSOR: '{{u|u||ustawienia u|ustawień u}}rządzeni{{a podłączonego do EMS-ESP|e||a podłączonego do EMS-ESP|a podłączonego do EMS-ESP}}',
|
||||||
ANALOG_SENSORS: 'Urządzenia podłączone do EMS-ESP',
|
ANALOG_SENSORS: 'Urządzenia podłączone do EMS-ESP',
|
||||||
SETTINGS: 'ustawie{{nia|ń|}}',
|
SETTINGS: 'ustawienia',
|
||||||
UPDATED_OF: 'Zaktualizowano {0}.',
|
UPDATED_OF: 'Zaktualizowano {0}.',
|
||||||
UPDATE_OF: 'Aktualizacja {0}',
|
UPDATE_OF: 'Aktualizacja {0}',
|
||||||
REMOVED_OF: 'Usunięto ustawienia {0}.',
|
REMOVED_OF: 'Usunięto ustawienia {0}.',
|
||||||
@@ -126,7 +126,6 @@ const pl: BaseTranslation = {
|
|||||||
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
|
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
|
||||||
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
|
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
|
||||||
UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
|
UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
|
||||||
HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem',
|
|
||||||
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica',
|
ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica',
|
||||||
TRIGGER_TIME: 'Wyzwalaj po czasie',
|
TRIGGER_TIME: 'Wyzwalaj po czasie',
|
||||||
@@ -146,13 +145,13 @@ const pl: BaseTranslation = {
|
|||||||
MINUTES: 'minut',
|
MINUTES: 'minut',
|
||||||
HOURS: 'godzin',
|
HOURS: 'godzin',
|
||||||
RESTART: 'Restart',
|
RESTART: 'Restart',
|
||||||
RESTART_TEXT: 'Aby zastosować wprowadzone zmiany, interfejs EMS-ESP {{musi zostać|zostanie|}} uruchomiony ponowni{{e.|e|}}',
|
RESTART_TEXT: 'Aby zastosować wprowadzone zmiany interfejs EMS-ESP musi zostać zrestartowany.',
|
||||||
RESTART_CONFIRM: 'Na pewno chcesz zrestartować interfejs EMS-ESP?',
|
RESTART_CONFIRM: 'Na pewno chcesz zrestartować interfejs EMS-ESP?',
|
||||||
COMMAND: '{{Komenda|KOMENDA|}}',
|
COMMAND: '{{Komenda|KOMENDA|}}',
|
||||||
CUSTOMIZATIONS_RESTART: 'Wszystkie personalizacje zostały usunięte. Restartuję...',
|
CUSTOMIZATIONS_RESTART: 'Wszystkie personalizacje zostały usunięte. Restartuję...',
|
||||||
CUSTOMIZATIONS_FULL: 'Wybrano za dużo obiektów. Wprowadź zmiany w mniejszych partiach.',
|
CUSTOMIZATIONS_FULL: 'Wybrano za dużo obiektów. Wprowadź zmiany w mniejszych partiach.',
|
||||||
CUSTOMIZATIONS_SAVED: 'Personalizacje zostały zapisane.',
|
CUSTOMIZATIONS_SAVED: 'Personalizacje zostały zapisane.',
|
||||||
CUSTOMIZATIONS_HELP_1: 'Wybierz urządzenie EMS, a następnie dostosuj opcje lub kliknij na nazwie encji by tę nazwę zmienić',
|
CUSTOMIZATIONS_HELP_1: 'Wybierz urządzenie EMS, dostosuj opcje lub kliknij by zmienić nazwę encji.',
|
||||||
CUSTOMIZATIONS_HELP_2: 'oznacz jako ulubioną',
|
CUSTOMIZATIONS_HELP_2: 'oznacz jako ulubioną',
|
||||||
CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu',
|
CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu',
|
||||||
CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API',
|
CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API',
|
||||||
@@ -164,13 +163,14 @@ const pl: BaseTranslation = {
|
|||||||
NAME: '{{Nazwa|nazwa|}}',
|
NAME: '{{Nazwa|nazwa|}}',
|
||||||
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
||||||
DEVICE_ENTITIES: 'Encje urządzenia',
|
DEVICE_ENTITIES: 'Encje urządzenia',
|
||||||
SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
|
SUPPORT_INFORMATION: 'Informacje dotyczące wsparcia',
|
||||||
CLICK_HERE: 'Kliknij tu',
|
CLICK_HERE: 'Kliknij tu',
|
||||||
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP, skorzystaj z wiki w internecie',
|
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP skorzystaj z wiki w internecie',
|
||||||
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
||||||
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić problem',
|
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić 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 dołączyć informacji o swoim systemie!',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP jest darmowym projektem typu open-source. Aby go wesprzeć, rozważ przyznanie nam gwiazdki na Github!',
|
HELP_INFORMATION_5: 'EMS-ESP jest darmowym projektem typu open-source. Aby go wesprzeć, rozważ przyznanie nam gwiazdki na Github!',
|
||||||
|
SUPPORT_INFO: 'Pobierz informacje',
|
||||||
UPLOAD: 'Wysyłanie',
|
UPLOAD: 'Wysyłanie',
|
||||||
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
||||||
ABORTED: 'zostało przerwane!',
|
ABORTED: 'zostało przerwane!',
|
||||||
@@ -194,19 +194,21 @@ const pl: BaseTranslation = {
|
|||||||
RELEASE_IS: 'wydanie to',
|
RELEASE_IS: 'wydanie to',
|
||||||
RELEASE_NOTES: 'lista zmian',
|
RELEASE_NOTES: 'lista zmian',
|
||||||
EMS_ESP_VER: 'Wersja EMS-ESP',
|
EMS_ESP_VER: 'Wersja EMS-ESP',
|
||||||
|
PLATFORM: 'Urządzenie (platforma / SDK)',
|
||||||
UPTIME: 'Czas działania systemu',
|
UPTIME: 'Czas działania systemu',
|
||||||
|
CPU_FREQ: 'Taktowanie CPU',
|
||||||
HEAP: 'HEAP (wolne / maksymalny przydział)',
|
HEAP: 'HEAP (wolne / maksymalny przydział)',
|
||||||
PSRAM: 'PSRAM (rozmiar / wolne)',
|
PSRAM: 'PSRAM (rozmiar / wolne)',
|
||||||
FLASH: 'FLASH (rozmiar / taktowanie)',
|
FLASH: 'FLASH (rozmiar / taktowanie)',
|
||||||
APPSIZE: 'Aplikacja (partycja: wykorzystane / wolne)',
|
APPSIZE: 'Aplikacja (wykorzystane / wolne)',
|
||||||
FILESYSTEM: 'System plików (wykorzystane / wolne)',
|
FILESYSTEM: 'System plików (wykorzystane / wolne)',
|
||||||
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
||||||
COMPACT: 'Kompaktowy',
|
COMPACT: 'Kompaktowy',
|
||||||
ENABLE_OTA: 'Aktywuj aktualizację OTA',
|
ENABLE_OTA: 'Aktywuj aktualizację OTA',
|
||||||
DOWNLOAD_CUSTOMIZATION_TEXT: 'Pobierz personalizacje.',
|
DOWNLOAD_CUSTOMIZATION_TEXT: 'Pobierz personalizacje.',
|
||||||
DOWNLOAD_SCHEDULE_TEXT: 'Pobierz harmonogram zdarzeń.',
|
DOWNLOAD_SCHEDULE_TEXT: 'Pobierz harmonogram zdarzeń.',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uwaga! Plik z ustawieniami zawiera hasła oraz inne wrażliwe informacje systemowe! Nie udostepniaj go pochopnie!',
|
DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uważaj jeśli udostępniasz plik z ustawieniami, ponieważ zawiera on hasła oraz inne wrażliwe informacje!',
|
||||||
UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji z sumą kontrolną (.md5).',
|
UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji (.md5).',
|
||||||
UPLOADING: 'Wysłano',
|
UPLOADING: 'Wysłano',
|
||||||
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!',
|
||||||
@@ -279,15 +281,14 @@ const pl: BaseTranslation = {
|
|||||||
SCAN_AGAIN: 'Skanuj ponownie',
|
SCAN_AGAIN: 'Skanuj ponownie',
|
||||||
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
||||||
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
||||||
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi i włączyć ETH',
|
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi', // and enable ETH // TODO translate
|
||||||
NETWORK_BLANK_BSSID: 'pozostaw puste aby używać tylko SSID',
|
|
||||||
TX_POWER: 'Moc nadawania',
|
TX_POWER: 'Moc nadawania',
|
||||||
HOSTNAME: 'Nazwa w sieci',
|
HOSTNAME: 'Nazwa w sieci',
|
||||||
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
||||||
NETWORK_LOW_BAND: 'Używaj mniejszej szerokości pasma WiFi (20MHz)',
|
NETWORK_LOW_BAND: 'Używaj mniejszej szerokości pasma WiFi (20MHz)',
|
||||||
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS',
|
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS',
|
||||||
NETWORK_ENABLE_CORS: 'Włącz wsparcie dla CORS',
|
NETWORK_ENABLE_CORS: 'Włącz wsparcie dla CORS',
|
||||||
NETWORK_CORS_ORIGIN: 'CORS Origin',
|
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||||
NETWORK_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
|
NETWORK_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
|
||||||
NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
|
NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
|
||||||
NETWORK_GATEWAY: 'Brama',
|
NETWORK_GATEWAY: 'Brama',
|
||||||
@@ -318,18 +319,10 @@ const pl: BaseTranslation = {
|
|||||||
CUSTOM_ENTITIES: '{{N|n|}}iestandardowe{{|j|}} encj{{e|i|}}',
|
CUSTOM_ENTITIES: '{{N|n|}}iestandardowe{{|j|}} encj{{e|i|}}',
|
||||||
ENTITIES_HELP_1: 'Zdefiniuj niestandardowe encje dla magistrali EMS.',
|
ENTITIES_HELP_1: 'Zdefiniuj niestandardowe encje dla magistrali EMS.',
|
||||||
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
||||||
WRITEABLE: 'Zapisywalna',
|
WRITEABLE: 'zapisywalna',
|
||||||
SHOWING: 'Wyświetlane',
|
SHOWING: 'Wyświetlane',
|
||||||
SEARCH: 'Szukaj',
|
SEARCH: 'Szukaj',
|
||||||
CERT: 'Certyfikat główny TLS (pozostaw puste dla TLS-insecure)',
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'Włącz wsparcie dla TLS',
|
|
||||||
ON: 'włączony',
|
|
||||||
OFF: 'wyłączony',
|
|
||||||
POLARITY: 'Typ przekaźnika',
|
|
||||||
ACTIVEHIGH: 'Wyzwalany stanem wysokim',
|
|
||||||
ACTIVELOW: 'Wyzwalany stanem niskim',
|
|
||||||
UNCHANGED: 'Zachowaj stan',
|
|
||||||
ALWAYS: 'Zawsze'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
@@ -1,335 +0,0 @@
|
|||||||
import type { Translation } from '../i18n-types';
|
|
||||||
/* prettier-ignore */
|
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
const sk: Translation = {
|
|
||||||
LANGUAGE: 'Jazyk',
|
|
||||||
RETRY: 'Opakovať',
|
|
||||||
LOADING: 'Načítanie',
|
|
||||||
IS_REQUIRED: '{0} je požadovaných',
|
|
||||||
SIGN_IN: 'Prihlásiť sa',
|
|
||||||
SIGN_OUT: 'Odhlásiť sa',
|
|
||||||
USERNAME: 'Užívateľské meno',
|
|
||||||
PASSWORD: 'Heslo',
|
|
||||||
SU_PASSWORD: 'su heslo',
|
|
||||||
DASHBOARD: 'Panel',
|
|
||||||
SETTINGS_OF: '{0} Nastavenia',
|
|
||||||
HELP_OF: '{0} Pomoc',
|
|
||||||
LOGGED_IN: 'Prihlásený ako {name}',
|
|
||||||
PLEASE_SIGNIN: 'Ak chcete pokračovať, prihláste sa',
|
|
||||||
UPLOAD_SUCCESSFUL: 'Nahratie úspešné',
|
|
||||||
DOWNLOAD_SUCCESSFUL: 'Stiahnutie úspešné',
|
|
||||||
INVALID_LOGIN: 'Nesprávne prihlasovacie údaje',
|
|
||||||
NETWORK: 'Sieť',
|
|
||||||
SECURITY: 'Zabezpečenie',
|
|
||||||
ONOFF_CAP: 'ZAP/VYP',
|
|
||||||
ONOFF: 'zap/vyp',
|
|
||||||
TYPE: 'Typ',
|
|
||||||
DESCRIPTION: 'Popis',
|
|
||||||
ENTITIES: 'Entity',
|
|
||||||
REFRESH: 'Obnoviť',
|
|
||||||
EXPORT: 'Export',
|
|
||||||
DEVICE_DETAILS: 'Detaily zariadenia',
|
|
||||||
ID_OF: '{0} ID',
|
|
||||||
DEVICE: 'Zariadenie',
|
|
||||||
PRODUCT: 'Produkt',
|
|
||||||
VERSION: 'Verzia',
|
|
||||||
BRAND: 'Značka',
|
|
||||||
ENTITY_NAME: 'Názov entity',
|
|
||||||
VALUE: '{{Value|value}}',
|
|
||||||
DEVICE_DATA: 'Dáta zariadenia',
|
|
||||||
SENSOR_DATA: 'Dáta snímača',
|
|
||||||
DEVICES: 'Zariadenia',
|
|
||||||
SENSORS: 'Snímače',
|
|
||||||
RUN_COMMAND: 'Volať príkaz',
|
|
||||||
CHANGE_VALUE: 'Zmena hodnoty',
|
|
||||||
CANCEL: 'Zrušiť',
|
|
||||||
RESET: 'Reset',
|
|
||||||
APPLY_CHANGES: 'Aplikovať zmeny ({0})',
|
|
||||||
UPDATE: 'Aktualizovať',
|
|
||||||
EXECUTE: 'Spustiť',
|
|
||||||
REMOVE: 'Odstrániť',
|
|
||||||
PROBLEM_UPDATING: 'Problém s aktualizáciou',
|
|
||||||
PROBLEM_LOADING: 'Problém s načítaním',
|
|
||||||
ANALOG_SENSOR: 'Analógový snímač',
|
|
||||||
ANALOG_SENSORS: 'Analógové snímače',
|
|
||||||
SETTINGS: 'Nastavenia',
|
|
||||||
UPDATED_OF: '{0} aktualizovaných',
|
|
||||||
UPDATE_OF: '{0} aktualizované',
|
|
||||||
REMOVED_OF: '{0} odstránených',
|
|
||||||
DELETION_OF: '{0} zmazaných',
|
|
||||||
OFFSET: 'Ofset',
|
|
||||||
FACTOR: 'Faktor',
|
|
||||||
FREQ: 'Frekvencia',
|
|
||||||
DUTY_CYCLE: 'Duty Cycle',
|
|
||||||
UNIT: 'UoM',
|
|
||||||
STARTVALUE: 'Počiatočná hodnota',
|
|
||||||
WARN_GPIO: 'Upozornenie: Buďte opatrní pri priraďovaní GPIO!',
|
|
||||||
EDIT: 'Editovať',
|
|
||||||
SENSOR: 'Snímač',
|
|
||||||
TEMP_SENSOR: 'Snímač teploty',
|
|
||||||
TEMP_SENSORS: 'Snímače teploty',
|
|
||||||
WRITE_CMD_SENT: 'Príkaz zápisu bol odoslaný',
|
|
||||||
EMS_BUS_WARNING: 'Zbernica EMS odpojená. Ak toto upozornenie pretrváva aj po niekoľkých sekundách, skontrolujte nastavenia a profil dosky',
|
|
||||||
EMS_BUS_SCANNING: 'Zisťovanie EMS zariadení...',
|
|
||||||
CONNECTED: 'Pripojené',
|
|
||||||
TX_ISSUES: 'Problémy s Tx – skontrolujte Tx režim',
|
|
||||||
DISCONNECTED: 'Odpojené',
|
|
||||||
EMS_SCAN: 'Naozaj chcete spustiť úplnú kontrolu zariadenia zbernice EMS?',
|
|
||||||
EMS_BUS_STATUS: 'Stav zbernice EMS',
|
|
||||||
ACTIVE_DEVICES: 'Aktívne zariadenia a snímače',
|
|
||||||
EMS_DEVICE: 'EMS zariadenie',
|
|
||||||
SUCCESS: 'ÚSPEŠNÉ',
|
|
||||||
FAIL: 'ZLYHANIE',
|
|
||||||
QUALITY: 'KVALITA',
|
|
||||||
SCAN_DEVICES: 'Scan pre nové zariadenia',
|
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS zbernica & stav aktivity',
|
|
||||||
SCAN: 'Scan',
|
|
||||||
STATUS_NAMES: [
|
|
||||||
'EMS Telegramy prijaté (Rx)',
|
|
||||||
'EMS Čítania (Tx)',
|
|
||||||
'EMS Zápisy (Tx)',
|
|
||||||
'Čítanie snímača teploty',
|
|
||||||
'Analógové snímanie',
|
|
||||||
'MQTT Publikovanie',
|
|
||||||
'API volania',
|
|
||||||
'Syslog správy'
|
|
||||||
],
|
|
||||||
NUM_DEVICES: '{num} Zariadenia{{s}}',
|
|
||||||
NUM_TEMP_SENSORS: '{num} Teplotné snímače{{s}}',
|
|
||||||
NUM_ANALOG_SENSORS: '{num} Analógové snímače{{s}}',
|
|
||||||
NUM_DAYS: '{num} dní{{s}}',
|
|
||||||
NUM_SECONDS: '{num} sekúnd{{s}}',
|
|
||||||
NUM_HOURS: '{num} hodín{{s}}',
|
|
||||||
NUM_MINUTES: '{num} minút{{s}}',
|
|
||||||
APPLICATION_SETTINGS: 'Nastavenia aplikácie',
|
|
||||||
CUSTOMIZATIONS: 'Prispôsobenia',
|
|
||||||
APPLICATION_RESTARTING: 'EMS-ESP sa reštartuje',
|
|
||||||
INTERFACE_BOARD_PROFILE: 'Profil boardu rozhrania',
|
|
||||||
BOARD_PROFILE_TEXT: 'Vyberte vopred nakonfigurovaný profil dosky rozhrania zo zoznamu nižšie alebo vyberte možnosť Vlastné a nakonfigurujte svoje vlastné hardvérové nastavenia',
|
|
||||||
BOARD_PROFILE: 'Board profil',
|
|
||||||
CUSTOM: 'Vlastné',
|
|
||||||
GPIO_OF: '{0} GPIO',
|
|
||||||
BUTTON: 'Tlačidlo',
|
|
||||||
TEMPERATURE: 'Teplota',
|
|
||||||
PHY_TYPE: 'Eth PHY Typ',
|
|
||||||
DISABLED: 'zakázané',
|
|
||||||
TX_MODE: 'Tx režim',
|
|
||||||
HARDWARE: 'Hardware',
|
|
||||||
EMS_BUS: '{{BUS|EMS BUS}}',
|
|
||||||
GENERAL_OPTIONS: 'Všeobecné možnosti',
|
|
||||||
LANGUAGE_ENTITIES: 'Jazyk (pre entity zariadenia)',
|
|
||||||
HIDE_LED: 'Skryť LED',
|
|
||||||
ENABLE_TELNET: 'Povoliť Telnet konzolu',
|
|
||||||
ENABLE_ANALOG: 'Povoliť analógové snímače',
|
|
||||||
CONVERT_FAHRENHEIT: 'Previesť hodnoty teploty na fahrenheity',
|
|
||||||
BYPASS_TOKEN: 'Vynechajte autorizáciu prístupového tokenu pri volaniach API',
|
|
||||||
READONLY: 'Povoliť režim len na čítanie (blokuje všetky odchádzajúce príkazy EMS Tx Write)',
|
|
||||||
UNDERCLOCK_CPU: 'Podtaktovanie rýchlosti procesora',
|
|
||||||
HEATINGOFF: 'Spustite kotol s núteným vykurovaním',
|
|
||||||
ENABLE_SHOWER_TIMER: 'Povoliť časovač sprchovania',
|
|
||||||
ENABLE_SHOWER_ALERT: 'Povoliť upozornenie na sprchu',
|
|
||||||
TRIGGER_TIME: 'Čas spustenia',
|
|
||||||
COLD_SHOT_DURATION: 'Trvanie studeného záberu',
|
|
||||||
FORMATTING_OPTIONS: 'Možnosti formátovania',
|
|
||||||
BOOLEAN_FORMAT_DASHBOARD: 'Panel Boolean formát',
|
|
||||||
BOOLEAN_FORMAT_API: 'Boolean formát API/MQTT',
|
|
||||||
ENUM_FORMAT: 'Enum formát API/MQTT',
|
|
||||||
INDEX: 'Index',
|
|
||||||
ENABLE_PARASITE: 'Povolenie parazitného napájania',
|
|
||||||
LOGGING: 'Logovanie',
|
|
||||||
LOG_HEX: 'Záznam telegramov EMS v hexadecimálnej sústave',
|
|
||||||
ENABLE_SYSLOG: 'Povoliť Syslog',
|
|
||||||
LOG_LEVEL: 'Log úroveň',
|
|
||||||
MARK_INTERVAL: 'Označenie intervalu',
|
|
||||||
SECONDS: 'sekundy',
|
|
||||||
MINUTES: 'minúty',
|
|
||||||
HOURS: 'hodiny',
|
|
||||||
RESTART: 'Reštart',
|
|
||||||
RESTART_TEXT: 'EMS-ESP sa musí reštartovať, aby sa použili zmenené systémové nastavenia',
|
|
||||||
RESTART_CONFIRM: 'Ste si istí, že chcete reštartovať EMS-ESP?',
|
|
||||||
COMMAND: 'Príkaz',
|
|
||||||
CUSTOMIZATIONS_RESTART: 'Ste si istí, že chcete reštartovať EMS-ESP?',
|
|
||||||
CUSTOMIZATIONS_FULL: 'Vybrané subjekty prekročili limit. Prosím, ukladajte v dávkach',
|
|
||||||
CUSTOMIZATIONS_SAVED: 'Uložené prispôsobenia',
|
|
||||||
CUSTOMIZATIONS_HELP_1: 'Vyberte zariadenie a prispôsobte možnosti entít alebo kliknutím premenujte',
|
|
||||||
CUSTOMIZATIONS_HELP_2: 'označiť ako obľúbené',
|
|
||||||
CUSTOMIZATIONS_HELP_3: 'zakázať akciu zápisu',
|
|
||||||
CUSTOMIZATIONS_HELP_4: 'vylúčiť z MQTT a API',
|
|
||||||
CUSTOMIZATIONS_HELP_5: 'skryť z panela',
|
|
||||||
CUSTOMIZATIONS_HELP_6: 'odstrániť z pamäte',
|
|
||||||
SELECT_DEVICE: 'Zvoliť zariadenie',
|
|
||||||
SET_ALL: 'nastaviť všetko',
|
|
||||||
OPTIONS: 'Možnosti',
|
|
||||||
NAME: 'Názov',
|
|
||||||
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
|
||||||
DEVICE_ENTITIES: 'Entity zariadenia',
|
|
||||||
SUPPORT_INFORMATION: 'Informácie o podpore',
|
|
||||||
CLICK_HERE: 'Kliknite tu',
|
|
||||||
HELP_INFORMATION_1: 'Navštívte online wiki, kde nájdete pokyny na konfiguráciu EMS-ESP',
|
|
||||||
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_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: 'EMS-ESP je bezplatný a open source projekt. Podporte jeho budúci vývoj tým, že mu dáte hviezdičku na Github!',
|
|
||||||
UPLOAD: 'Nahrať',
|
|
||||||
DOWNLOAD: '{{S|s|s}}tiahnuť',
|
|
||||||
ABORTED: 'zrušené',
|
|
||||||
FAILED: 'chybné',
|
|
||||||
SUCCESSFUL: 'úspešné',
|
|
||||||
SYSTEM: 'Systém',
|
|
||||||
LOG_OF: '{0} Log',
|
|
||||||
STATUS_OF: '{0} Stav',
|
|
||||||
UPLOAD_DOWNLOAD: 'Nahrať/Stiahnuť',
|
|
||||||
VERSION_ON: 'Momentálne ste vo verzii',
|
|
||||||
SYSTEM_APPLY_FIRMWARE: 'na použitie nového firmvéru',
|
|
||||||
CLOSE: 'Zatvoriť',
|
|
||||||
USE: 'Použiť',
|
|
||||||
FACTORY_RESET: 'Továrenské nastavenia',
|
|
||||||
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?',
|
|
||||||
VERSION_CHECK: 'Kontrola verzie',
|
|
||||||
THE_LATEST: 'Posledná',
|
|
||||||
OFFICIAL: 'officiálna',
|
|
||||||
DEVELOPMENT: 'vývojárska',
|
|
||||||
RELEASE_IS: 'vydanie je',
|
|
||||||
RELEASE_NOTES: 'poznámky k vydaniu',
|
|
||||||
EMS_ESP_VER: 'EMS-ESP verzia',
|
|
||||||
UPTIME: 'Beh systému',
|
|
||||||
HEAP: 'Zásobník (voľné / max pridelenie)',
|
|
||||||
PSRAM: 'PSRAM (Veľkosť / Voľné)',
|
|
||||||
FLASH: 'Flash chip (Veľkosť / Rýchlosť)',
|
|
||||||
APPSIZE: 'Applikácia (Priečka: Použité / Voľné)',
|
|
||||||
FILESYSTEM: 'Súborový systém (Použité / Voľné)',
|
|
||||||
BUFFER_SIZE: 'Maximálna veľkosť vyrovnávacej pamäte',
|
|
||||||
COMPACT: 'Kompaktné',
|
|
||||||
ENABLE_OTA: 'Povoliť OTA aktualizácie',
|
|
||||||
DOWNLOAD_CUSTOMIZATION_TEXT: 'Stiahnutie prispôsobení entity',
|
|
||||||
DOWNLOAD_SCHEDULE_TEXT: 'Stiahnutie plánovača udalostí',
|
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Stiahnite si nastavenia aplikácie. Pri zdieľaní nastavení buďte opatrní, pretože tento súbor obsahuje heslá a iné citlivé systémové informácie.',
|
|
||||||
UPLOAD_TEXT: 'Najskôr nahrajte nový súbor firmvéru (.bin), nastavenia alebo prispôsobenia (.json), pre voliteľné overenie nahrajte súbor (.md5)',
|
|
||||||
UPLOADING: 'Nahrávanie',
|
|
||||||
UPLOAD_DROP_TEXT: 'Zahodiť súbor alebo kliknúť sem',
|
|
||||||
ERROR: 'Neočakávaná chyba, prosím skúste to znova',
|
|
||||||
TIME_SET: 'Nastavený čas',
|
|
||||||
MANAGE_USERS: 'Správa používateľov',
|
|
||||||
IS_ADMIN: 'je Admin',
|
|
||||||
USER_WARNING: 'Musíte mať nakonfigurovaného aspoň jedného používateľa administrátora',
|
|
||||||
ADD: 'Pridať',
|
|
||||||
ACCESS_TOKEN_FOR: 'Prístupový token pre',
|
|
||||||
ACCESS_TOKEN_TEXT: 'Nižšie uvedený token sa používa pri volaniach REST API, ktoré vyžadujú autorizáciu. Môže byť odovzdaný buď ako token Bearer v hlavičke Authorization (Autorizácia), alebo v parametri dotazu URL access_token.',
|
|
||||||
GENERATING_TOKEN: 'Generovanie tokenu',
|
|
||||||
USER: 'Užívateľ',
|
|
||||||
MODIFY: 'Upraviť',
|
|
||||||
SU_TEXT: 'Heslo su (superužívateľ) sa používa na podpisovanie autentifikačných tokenov a tiež na povolenie oprávnení správcu v rámci konzoly.',
|
|
||||||
NOT_ENABLED: 'Nie je povolené',
|
|
||||||
ERRORS_OF: '{0} errory',
|
|
||||||
DISCONNECT_REASON: 'Dôvod odpojenia',
|
|
||||||
ENABLE_MQTT: 'Povoliť MQTT',
|
|
||||||
BROKER: 'Broker',
|
|
||||||
CLIENT: 'Klient',
|
|
||||||
BASE_TOPIC: 'Base',
|
|
||||||
OPTIONAL: 'voliteľné',
|
|
||||||
FORMATTING: 'Formátovanie',
|
|
||||||
MQTT_FORMAT: 'Formát témy/záťaže',
|
|
||||||
MQTT_NEST_1: 'Vnorené do jednej témy',
|
|
||||||
MQTT_NEST_2: 'Ako jednotlivé témy',
|
|
||||||
MQTT_RESPONSE: 'Publikovanie výstupu príkazu do témy `response`',
|
|
||||||
MQTT_PUBLISH_TEXT_1: 'Zverejňovanie tém jednotlivých hodnôt pri zmene',
|
|
||||||
MQTT_PUBLISH_TEXT_2: 'Publikovanie do tém príkazov (ioBroker)',
|
|
||||||
MQTT_PUBLISH_TEXT_3: 'Povolenie zisťovania MQTT',
|
|
||||||
MQTT_PUBLISH_TEXT_4: 'Predpona tém Discovery',
|
|
||||||
MQTT_PUBLISH_TEXT_5: 'Typ zistenia',
|
|
||||||
MQTT_PUBLISH_INTERVALS: 'Intervaly zverejňovania',
|
|
||||||
MQTT_INT_BOILER: 'Kotly a tepelné čerpadlá',
|
|
||||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
|
||||||
MQTT_INT_SOLAR: 'Solárne moduly',
|
|
||||||
MQTT_INT_MIXER: 'Zmiešavacie moduley',
|
|
||||||
MQTT_QUEUE: 'Fronta MQTT',
|
|
||||||
DEFAULT: 'Predvolené',
|
|
||||||
MQTT_ENTITY_FORMAT: 'ID formát entity',
|
|
||||||
MQTT_ENTITY_FORMAT_0: 'Jedna inštancia, dlhý názov (v3.4)',
|
|
||||||
MQTT_ENTITY_FORMAT_1: 'Jedna inštancia, krátky názov',
|
|
||||||
MQTT_ENTITY_FORMAT_2: 'Viacero inštancií, krátky názov',
|
|
||||||
MQTT_CLEAN_SESSION: 'Nastavenie čistej relácie',
|
|
||||||
MQTT_RETAIN_FLAG: 'Vždy nastaviť príznak Retain',
|
|
||||||
INACTIVE: 'Neaktívne',
|
|
||||||
ACTIVE: 'Aktívne',
|
|
||||||
UNKNOWN: 'Neznáme',
|
|
||||||
SET_TIME: 'Nastavený čas',
|
|
||||||
SET_TIME_TEXT: 'Na nastavenie času zadajte miestny dátum a čas nižšie',
|
|
||||||
LOCAL_TIME: 'Lokálny čas',
|
|
||||||
UTC_TIME: 'UTC čas',
|
|
||||||
ENABLE_NTP: 'Povoliť NTP',
|
|
||||||
NTP_SERVER: 'NTP Server',
|
|
||||||
TIME_ZONE: 'Časová zóna',
|
|
||||||
ACCESS_POINT: 'Prístupový bod',
|
|
||||||
AP_PROVIDE: 'Povoliť prístupový bod',
|
|
||||||
AP_PROVIDE_TEXT_1: 'vždy',
|
|
||||||
AP_PROVIDE_TEXT_2: 'keď WiFi je odpojená',
|
|
||||||
AP_PROVIDE_TEXT_3: 'nikdy',
|
|
||||||
AP_PREFERRED_CHANNEL: 'Preferovaný kanál',
|
|
||||||
AP_HIDE_SSID: 'Skryť SSID',
|
|
||||||
AP_CLIENTS: 'AP klienti',
|
|
||||||
AP_MAX_CLIENTS: 'Max klientov',
|
|
||||||
AP_LOCAL_IP: 'Lokálna IP',
|
|
||||||
NETWORK_SCAN: 'Scan WiFi siete',
|
|
||||||
IDLE: 'Nečinné',
|
|
||||||
LOST: 'Stratené',
|
|
||||||
SCANNING: 'Scanovanie',
|
|
||||||
SCAN_AGAIN: 'Scanovať znova',
|
|
||||||
NETWORK_SCANNER: 'Sieťový scanner',
|
|
||||||
NETWORK_NO_WIFI: 'WiFi siete nenájdené',
|
|
||||||
NETWORK_BLANK_SSID: 'nechajte prázdne, ak chcete zakázať WiFi a povoliť ETH',
|
|
||||||
NETWORK_BLANK_BSSID: 'ponechajte prázdne, ak chcete používať iba SSID',
|
|
||||||
TX_POWER: 'Tx výkon',
|
|
||||||
HOSTNAME: 'Hostname',
|
|
||||||
NETWORK_DISABLE_SLEEP: 'Zakázanie režimu spánku WiFi',
|
|
||||||
NETWORK_LOW_BAND: 'Používanie menšej šírky pásma WiFi',
|
|
||||||
NETWORK_USE_DNS: 'Povoliť mDNS službu',
|
|
||||||
NETWORK_ENABLE_CORS: 'Povoliť CORS',
|
|
||||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
|
||||||
NETWORK_ENABLE_IPV6: 'Povoliť podporu IPv6',
|
|
||||||
NETWORK_FIXED_IP: 'Použiť fixnú IP adresu',
|
|
||||||
NETWORK_GATEWAY: 'Brána',
|
|
||||||
NETWORK_SUBNET: 'Maska podsiete',
|
|
||||||
NETWORK_DNS: 'DNS servery',
|
|
||||||
ADDRESS_OF: '{0} adries',
|
|
||||||
ADMIN: 'Admin',
|
|
||||||
GUEST: 'Hosť',
|
|
||||||
NEW: 'Nová',
|
|
||||||
NEW_NAME_OF: 'Nových {0} názvov',
|
|
||||||
ENTITY: 'entita',
|
|
||||||
MIN: 'min',
|
|
||||||
MAX: 'max',
|
|
||||||
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
|
|
||||||
BLOCK_NAVIGATE_2: 'Ak prejdete na inú stránku, neuložené zmeny sa stratia. Ste si istí, že chcete opustiť túto stránku?',
|
|
||||||
STAY: 'Zostať',
|
|
||||||
LEAVE: 'Opustiť',
|
|
||||||
SCHEDULER: 'Plánovač',
|
|
||||||
SCHEDULER_HELP_1: 'Automatizujte príkazy pridaním naplánovaných udalostí nižšie. Nastavte jedinečné meno na aktiváciu/deaktiváciu cez API/MQTT.',
|
|
||||||
SCHEDULER_HELP_2: 'Použite 00:00 na jednorazové spustenie pri štarte',
|
|
||||||
SCHEDULE: 'Plánovať',
|
|
||||||
TIME: 'Čas',
|
|
||||||
TIMER: 'Časovač',
|
|
||||||
SCHEDULE_UPDATED: 'Plánovanie aktualizované',
|
|
||||||
SCHEDULE_TIMER_1: 'pri spustení',
|
|
||||||
SCHEDULE_TIMER_2: 'každú minútu',
|
|
||||||
SCHEDULE_TIMER_3: 'každú hodinu',
|
|
||||||
CUSTOM_ENTITIES: 'Vlastné entity',
|
|
||||||
ENTITIES_HELP_1: 'Získavanie vlastných entít zo zbernice EMS',
|
|
||||||
ENTITIES_UPDATED: 'Aktualizované entity',
|
|
||||||
WRITEABLE: 'Zapísateľný',
|
|
||||||
SHOWING: 'Zobrazenie',
|
|
||||||
SEARCH: 'Vyhľadať',
|
|
||||||
CERT: 'Koreňový certifikát TLS (ak chcete vypnúť TLS, nechajte prázdne)',
|
|
||||||
ENABLE_TLS: 'Povoliť TLS',
|
|
||||||
ON: 'Zap',
|
|
||||||
OFF: 'Vyp',
|
|
||||||
POLARITY: 'Polarita',
|
|
||||||
ACTIVEHIGH: 'Aktívny Vysoký',
|
|
||||||
ACTIVELOW: 'Aktívny Nízky',
|
|
||||||
UNCHANGED: 'Nezmenené',
|
|
||||||
ALWAYS: 'Vždy'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default sk;
|
|
||||||
@@ -126,7 +126,6 @@ const sv: Translation = {
|
|||||||
BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop',
|
BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop',
|
||||||
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
|
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
|
||||||
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
|
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
|
||||||
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer',
|
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning',
|
ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning',
|
||||||
TRIGGER_TIME: 'Aktiveringstid',
|
TRIGGER_TIME: 'Aktiveringstid',
|
||||||
@@ -171,6 +170,7 @@ const sv: Translation = {
|
|||||||
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: 'EMS-ESP är gratis och är öppen källkod. Bidra till utvecklingen genom att ge oss en stjärna på GitHub!',
|
HELP_INFORMATION_5: 'EMS-ESP är gratis och är öppen källkod. Bidra till utvecklingen genom att ge oss en stjärna på GitHub!',
|
||||||
|
SUPPORT_INFO: 'Supportinfo',
|
||||||
UPLOAD: 'Uppladdning',
|
UPLOAD: 'Uppladdning',
|
||||||
DOWNLOAD: '{{N|n|n}}edladdning',
|
DOWNLOAD: '{{N|n|n}}edladdning',
|
||||||
ABORTED: 'Avbruten',
|
ABORTED: 'Avbruten',
|
||||||
@@ -194,11 +194,13 @@ const sv: Translation = {
|
|||||||
RELEASE_IS: 'release är', // TODO translate
|
RELEASE_IS: 'release är', // TODO translate
|
||||||
RELEASE_NOTES: 'release-logg',
|
RELEASE_NOTES: 'release-logg',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
|
PLATFORM: 'Enhet (Plattform / SDK)',
|
||||||
UPTIME: 'Systemets Upptid',
|
UPTIME: 'Systemets Upptid',
|
||||||
|
CPU_FREQ: 'CPU-frekvens',
|
||||||
HEAP: 'Heap (Ledigt / Max allokerat)',
|
HEAP: 'Heap (Ledigt / Max allokerat)',
|
||||||
PSRAM: 'PSRAM (Storlek / Ledigt)',
|
PSRAM: 'PSRAM (Storlek / Ledigt)',
|
||||||
FLASH: 'Flashminne (Storlek / Hastighet)',
|
FLASH: 'Flashminne (Storlek / Hastighet)',
|
||||||
APPSIZE: 'Applikationer (Partition: Använt / Ledigt)',
|
APPSIZE: 'Applikationer (Använt / Ledigt)',
|
||||||
FILESYSTEM: 'Filsystem (Använt / Ledigt)',
|
FILESYSTEM: 'Filsystem (Använt / Ledigt)',
|
||||||
BUFFER_SIZE: 'Max Bufferstorlek',
|
BUFFER_SIZE: 'Max Bufferstorlek',
|
||||||
COMPACT: 'Komprimera',
|
COMPACT: 'Komprimera',
|
||||||
@@ -228,7 +230,7 @@ const sv: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'valfritt',
|
OPTIONAL: 'Valfritt',
|
||||||
FORMATTING: 'Formatering',
|
FORMATTING: 'Formatering',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nestlat i en topic.',
|
MQTT_NEST_1: 'Nestlat i en topic.',
|
||||||
@@ -280,7 +282,6 @@ const sv: Translation = {
|
|||||||
NETWORK_SCANNER: 'Hittade nätverk',
|
NETWORK_SCANNER: 'Hittade nätverk',
|
||||||
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
||||||
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate
|
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Värdnamn',
|
HOSTNAME: 'Värdnamn',
|
||||||
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
||||||
@@ -321,15 +322,7 @@ const sv: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'Aktivera TLS',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ const tr: Translation = {
|
|||||||
BYPASS_TOKEN: 'API bağlantılarında Erişim Jeton onaylamasını geç',
|
BYPASS_TOKEN: 'API bağlantılarında Erişim Jeton onaylamasını geç',
|
||||||
READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)',
|
READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)',
|
||||||
UNDERCLOCK_CPU: 'İşlemci hızını düşür',
|
UNDERCLOCK_CPU: 'İşlemci hızını düşür',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
|
||||||
ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al',
|
ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al',
|
||||||
ENABLE_SHOWER_ALERT: 'Duş Alarmını Devreye Al',
|
ENABLE_SHOWER_ALERT: 'Duş Alarmını Devreye Al',
|
||||||
TRIGGER_TIME: 'Tetikleme Zamanı',
|
TRIGGER_TIME: 'Tetikleme Zamanı',
|
||||||
@@ -171,6 +170,7 @@ const tr: Translation = {
|
|||||||
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: 'EMS-ESP ücretsiz ve açık kaynaklı bir projedir. Lütfen geliştirmeyi desteklemek için Githubda projeye yıldız verin!',
|
HELP_INFORMATION_5: 'EMS-ESP ücretsiz ve açık kaynaklı bir projedir. Lütfen geliştirmeyi desteklemek için Githubda projeye yıldız verin!',
|
||||||
|
SUPPORT_INFO: 'Destek Bilgisi',
|
||||||
UPLOAD: 'Yükleme',
|
UPLOAD: 'Yükleme',
|
||||||
DOWNLOAD: '{{İ|i|i}}İndirme',
|
DOWNLOAD: '{{İ|i|i}}İndirme',
|
||||||
ABORTED: 'iptal edildi',
|
ABORTED: 'iptal edildi',
|
||||||
@@ -194,11 +194,13 @@ const tr: Translation = {
|
|||||||
RELEASE_IS: 'release is', // TODO translate
|
RELEASE_IS: 'release is', // TODO translate
|
||||||
RELEASE_NOTES: 'yayınlanma notları',
|
RELEASE_NOTES: 'yayınlanma notları',
|
||||||
EMS_ESP_VER: 'EMS-ESP Sürümü',
|
EMS_ESP_VER: 'EMS-ESP Sürümü',
|
||||||
|
PLATFORM: 'Cihaz (Platform / SDK)',
|
||||||
UPTIME: 'Sistem Çalışma Süresi',
|
UPTIME: 'Sistem Çalışma Süresi',
|
||||||
|
CPU_FREQ: 'İşlemci frekansı',
|
||||||
HEAP: 'Yığın (Boş / Maksimum Tahsis)',
|
HEAP: 'Yığın (Boş / Maksimum Tahsis)',
|
||||||
PSRAM: 'PSRAM (Boyut / Boş)',
|
PSRAM: 'PSRAM (Boyut / Boş)',
|
||||||
FLASH: 'Flash Çipi (Boyut / Hız)',
|
FLASH: 'Flash Çipi (Boyut / Hız)',
|
||||||
APPSIZE: 'Uygulama (Bölme: Kullanılmış / Boş)',
|
APPSIZE: 'Uygulama (Kullanılmış / Boş)',
|
||||||
FILESYSTEM: 'Dosya Sistemi (Kullanılmış / Boş)',
|
FILESYSTEM: 'Dosya Sistemi (Kullanılmış / Boş)',
|
||||||
BUFFER_SIZE: 'En fazla bellek boyutu',
|
BUFFER_SIZE: 'En fazla bellek boyutu',
|
||||||
COMPACT: 'Sıkışık',
|
COMPACT: 'Sıkışık',
|
||||||
@@ -228,7 +230,7 @@ const tr: Translation = {
|
|||||||
BROKER: 'Aracı',
|
BROKER: 'Aracı',
|
||||||
CLIENT: 'İstemci',
|
CLIENT: 'İstemci',
|
||||||
BASE_TOPIC: 'Merkez',
|
BASE_TOPIC: 'Merkez',
|
||||||
OPTIONAL: 'seçenekli',
|
OPTIONAL: 'Seçenekli',
|
||||||
FORMATTING: 'Biçimlendiriliyor',
|
FORMATTING: 'Biçimlendiriliyor',
|
||||||
MQTT_FORMAT: 'Konu/Mesaj Biçimi',
|
MQTT_FORMAT: 'Konu/Mesaj Biçimi',
|
||||||
MQTT_NEST_1: 'Tek konu üzerine yerleşmiş',
|
MQTT_NEST_1: 'Tek konu üzerine yerleşmiş',
|
||||||
@@ -280,7 +282,6 @@ const tr: Translation = {
|
|||||||
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
||||||
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
||||||
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın', // TODO translate
|
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın', // TODO translate
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
|
||||||
TX_POWER: 'Aktarım gücü',
|
TX_POWER: 'Aktarım gücü',
|
||||||
HOSTNAME: 'Ana Makine Adı',
|
HOSTNAME: 'Ana Makine Adı',
|
||||||
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
||||||
@@ -321,15 +322,7 @@ const tr: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)',
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
ENABLE_TLS: 'TLS deveye al',
|
|
||||||
ON: 'On', // TODO translate
|
|
||||||
OFF: 'Off', // TODO translate
|
|
||||||
POLARITY: 'Polarity', // TODO translate
|
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
|
||||||
ALWAYS: 'Always' // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tr;
|
export default tr;
|
||||||
|
|||||||
@@ -20,15 +20,15 @@ const Dashboard: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/dashboard/devices" label={LL.DEVICES()} />
|
<Tab value="devices" label={LL.DEVICES()} />
|
||||||
<Tab value="/dashboard/sensors" label={LL.SENSORS()} />
|
<Tab value="sensors" label={LL.SENSORS()} />
|
||||||
<Tab value="/dashboard/status" label="Status" />
|
<Tab value="status" label="Status" />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="devices" element={<DashboardDevices />} />
|
<Route path="devices" element={<DashboardDevices />} />
|
||||||
<Route path="sensors" element={<DashboardSensors />} />
|
<Route path="sensors" element={<DashboardSensors />} />
|
||||||
<Route path="status" element={<DashboardStatus />} />
|
<Route path="status" element={<DashboardStatus />} />
|
||||||
<Route path="*" element={<Navigate replace to="/dashboard/devices" />} />
|
<Route path="/*" element={<Navigate replace to="devices" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||||
import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
|
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
|
|
||||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||||
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
|
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
|
||||||
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
|
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
|
||||||
@@ -27,7 +26,6 @@ import {
|
|||||||
Grid,
|
Grid,
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import { useRowSelect } from '@table-library/react-table-library/select';
|
import { useRowSelect } from '@table-library/react-table-library/select';
|
||||||
import { useSort, SortToggleType } from '@table-library/react-table-library/sort';
|
import { useSort, SortToggleType } from '@table-library/react-table-library/sort';
|
||||||
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
||||||
@@ -36,7 +34,6 @@ import { useRequest } from 'alova';
|
|||||||
import { useState, useContext, useEffect, useCallback, useLayoutEffect } from 'react';
|
import { useState, useContext, useEffect, useCallback, useLayoutEffect } from 'react';
|
||||||
|
|
||||||
import { IconContext } from 'react-icons';
|
import { IconContext } from 'react-icons';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import DashboardDevicesDialog from './DashboardDevicesDialog';
|
import DashboardDevicesDialog from './DashboardDevicesDialog';
|
||||||
import DeviceIcon from './DeviceIcon';
|
import DeviceIcon from './DeviceIcon';
|
||||||
@@ -55,17 +52,15 @@ import { AuthenticatedContext } from 'contexts/authentication';
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const DashboardDevices: FC = () => {
|
const DashboardDevices: FC = () => {
|
||||||
|
const [size, setSize] = useState([0, 0]);
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [size, setSize] = useState([0, 0]);
|
|
||||||
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
|
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
|
||||||
const [onlyFav, setOnlyFav] = useState(false);
|
const [onlyFav, setOnlyFav] = useState(false);
|
||||||
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
|
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
|
||||||
const [showDeviceInfo, setShowDeviceInfo] = useState<boolean>(false);
|
const [showDeviceInfo, setShowDeviceInfo] = useState<boolean>(false);
|
||||||
const [selectedDevice, setSelectedDevice] = useState<number>();
|
const [selectedDevice, setSelectedDevice] = useState<number>();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const { data: coreData, send: readCoreData } = useRequest(() => EMSESP.readCoreData(), {
|
const { data: coreData, send: readCoreData } = useRequest(() => EMSESP.readCoreData(), {
|
||||||
initialData: {
|
initialData: {
|
||||||
connected: true,
|
connected: true,
|
||||||
@@ -268,16 +263,13 @@ const DashboardDevices: FC = () => {
|
|||||||
}, [escFunction]);
|
}, [escFunction]);
|
||||||
|
|
||||||
const refreshData = () => {
|
const refreshData = () => {
|
||||||
if (!deviceValueDialogOpen) {
|
if (deviceValueDialogOpen) {
|
||||||
selectedDevice ? void readDeviceData(selectedDevice) : void readCoreData();
|
return;
|
||||||
}
|
}
|
||||||
};
|
if (selectedDevice) {
|
||||||
|
void readDeviceData(selectedDevice);
|
||||||
const customize = () => {
|
|
||||||
if (selectedDevice == 99) {
|
|
||||||
navigate('/settings/customentities');
|
|
||||||
} else {
|
} else {
|
||||||
navigate('/settings/customization', { state: selectedDevice });
|
void readCoreData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -295,50 +287,48 @@ const DashboardDevices: FC = () => {
|
|||||||
return sc;
|
return sc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makeCsvData = (columns: any, data: any) =>
|
||||||
|
data.reduce(
|
||||||
|
(csvString: any, rowItem: any) =>
|
||||||
|
csvString + columns.map(({ accessor }: any) => escapeCsvCell(accessor(rowItem))).join(';') + '\r\n',
|
||||||
|
columns.map(({ name }: any) => escapeCsvCell(name)).join(';') + '\r\n'
|
||||||
|
);
|
||||||
|
|
||||||
|
const downloadAsCsv = (columns: any, data: any, filename: string) => {
|
||||||
|
const csvData = makeCsvData(columns, data);
|
||||||
|
const csvFile = new Blob([csvData], { type: 'text/csv;charset:utf-8' });
|
||||||
|
const downloadLink = document.createElement('a');
|
||||||
|
|
||||||
|
downloadLink.download = filename;
|
||||||
|
downloadLink.href = window.URL.createObjectURL(csvFile);
|
||||||
|
document.body.appendChild(downloadLink);
|
||||||
|
downloadLink.click();
|
||||||
|
document.body.removeChild(downloadLink);
|
||||||
|
};
|
||||||
|
|
||||||
const hasMask = (id: string, mask: number) => (parseInt(id.slice(0, 2), 16) & mask) === mask;
|
const hasMask = (id: string, mask: number) => (parseInt(id.slice(0, 2), 16) & mask) === mask;
|
||||||
|
|
||||||
const handleDownloadCsv = () => {
|
const handleDownloadCsv = () => {
|
||||||
|
const columns = [
|
||||||
|
{ accessor: (dv: any) => dv.id.slice(2), name: LL.ENTITY_NAME(0) },
|
||||||
|
{
|
||||||
|
accessor: (dv: any) => (typeof dv.v === 'number' ? new Intl.NumberFormat().format(dv.v) : dv.v),
|
||||||
|
name: LL.VALUE(0)
|
||||||
|
},
|
||||||
|
{ accessor: (dv: any) => DeviceValueUOM_s[dv.u], name: 'UoM' }
|
||||||
|
];
|
||||||
|
|
||||||
const deviceIndex = coreData.devices.findIndex((d) => d.id === device_select.state.id);
|
const deviceIndex = coreData.devices.findIndex((d) => d.id === device_select.state.id);
|
||||||
if (deviceIndex === -1) {
|
if (deviceIndex === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename = coreData.devices[deviceIndex].tn + '_' + coreData.devices[deviceIndex].n;
|
const filename = coreData.devices[deviceIndex].tn + '_' + coreData.devices[deviceIndex].n;
|
||||||
|
|
||||||
const columns = [
|
downloadAsCsv(
|
||||||
{ accessor: (dv: DeviceValue) => dv.id.slice(2), name: LL.ENTITY_NAME(0) },
|
columns,
|
||||||
{
|
onlyFav ? deviceData.data.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE)) : deviceData.data,
|
||||||
accessor: (dv: DeviceValue) => (typeof dv.v === 'number' ? new Intl.NumberFormat().format(dv.v) : dv.v),
|
filename
|
||||||
name: LL.VALUE(1)
|
|
||||||
},
|
|
||||||
{ accessor: (dv: DeviceValue) => DeviceValueUOM_s[dv.u].replace(/[^a-zA-Z0-9]/g, ''), name: 'UoM' },
|
|
||||||
{
|
|
||||||
accessor: (dv: DeviceValue) => (dv.c && !hasMask(dv.id, DeviceEntityMask.DV_READONLY) ? 'yes' : 'no'),
|
|
||||||
name: LL.WRITEABLE()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: (dv: DeviceValue) =>
|
|
||||||
dv.h ? dv.h : dv.l ? dv.l.join(' | ') : dv.m !== undefined && dv.x !== undefined ? dv.m + ', ' + dv.x : '',
|
|
||||||
name: 'Range'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const data = onlyFav
|
|
||||||
? deviceData.data.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE))
|
|
||||||
: deviceData.data;
|
|
||||||
|
|
||||||
const csvData = data.reduce(
|
|
||||||
(csvString: any, rowItem: any) =>
|
|
||||||
csvString + columns.map(({ accessor }: any) => escapeCsvCell(accessor(rowItem))).join(';') + '\r\n',
|
|
||||||
columns.map(({ name }: any) => escapeCsvCell(name)).join(';') + '\r\n'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const csvFile = new Blob([csvData], { type: 'text/csv;charset:utf-8' });
|
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.download = filename;
|
|
||||||
downloadLink.href = window.URL.createObjectURL(csvFile);
|
|
||||||
document.body.appendChild(downloadLink);
|
|
||||||
downloadLink.click();
|
|
||||||
document.body.removeChild(downloadLink);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -350,7 +340,7 @@ const DashboardDevices: FC = () => {
|
|||||||
|
|
||||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
||||||
const id = Number(device_select.state.id);
|
const id = Number(device_select.state.id);
|
||||||
await writeDeviceValue({ id, c: devicevalue.c, v: devicevalue.v })
|
await writeDeviceValue({ id, devicevalue })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.WRITE_CMD_SENT());
|
toast.success(LL.WRITE_CMD_SENT());
|
||||||
})
|
})
|
||||||
@@ -420,35 +410,30 @@ const DashboardDevices: FC = () => {
|
|||||||
<MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} />
|
<MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coreData.connected && (
|
<Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}>
|
||||||
<Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}>
|
{(tableList: any) => (
|
||||||
{(tableList: any) => (
|
<>
|
||||||
<>
|
<Header>
|
||||||
<Header>
|
<HeaderRow>
|
||||||
<HeaderRow>
|
<HeaderCell stiff />
|
||||||
<HeaderCell stiff />
|
<HeaderCell resize>{LL.DESCRIPTION()}</HeaderCell>
|
||||||
<HeaderCell resize>{LL.DESCRIPTION()}</HeaderCell>
|
<HeaderCell stiff>{LL.TYPE(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.TYPE(0)}</HeaderCell>
|
</HeaderRow>
|
||||||
</HeaderRow>
|
</Header>
|
||||||
</Header>
|
<Body>
|
||||||
<Body>
|
{tableList.map((device: Device) => (
|
||||||
{tableList.map((device: Device) => (
|
<Row key={device.id} item={device}>
|
||||||
<Row key={device.id} item={device}>
|
<Cell stiff>
|
||||||
<Cell stiff>
|
<DeviceIcon type_id={device.t} />
|
||||||
<DeviceIcon type_id={device.t} />
|
</Cell>
|
||||||
</Cell>
|
<Cell>{device.n}</Cell>
|
||||||
<Cell>
|
<Cell stiff>{device.tn}</Cell>
|
||||||
{device.n}
|
</Row>
|
||||||
<span style={{ color: 'lightblue' }}> ({device.e})</span>
|
))}
|
||||||
</Cell>
|
</Body>
|
||||||
<Cell stiff>{device.tn}</Cell>
|
</>
|
||||||
</Row>
|
)}
|
||||||
))}
|
</Table>
|
||||||
</Body>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Table>
|
|
||||||
)}
|
|
||||||
</IconContext.Provider>
|
</IconContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -495,31 +480,21 @@ const DashboardDevices: FC = () => {
|
|||||||
right: 16,
|
right: 16,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
top: 128,
|
top: 128,
|
||||||
zIndex: 'modal',
|
maxHeight: () => size[1] - 210,
|
||||||
maxHeight: () => size[1] - 189,
|
zIndex: 'modal'
|
||||||
border: '1px solid #177ac9'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ border: '1px solid #177ac9' }}>
|
<Box sx={{ border: '1px solid #177ac9' }}>
|
||||||
<Typography noWrap variant="subtitle1" color="warning.main" sx={{ ml: 1 }}>
|
<Typography noWrap variant="subtitle1" color="warning.main" sx={{ mx: 1 }}>
|
||||||
{coreData.devices[deviceIndex].tn} | {coreData.devices[deviceIndex].n}
|
{coreData.devices[deviceIndex].n}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography sx={{ ml: 1 }} variant="subtitle2" color="primary">
|
<Typography sx={{ ml: 1 }} variant="subtitle2" color="primary">
|
||||||
{LL.SHOWING() +
|
{shown_data.length + ' ' + LL.ENTITIES(shown_data.length)}
|
||||||
' ' +
|
|
||||||
shown_data.length +
|
|
||||||
'/' +
|
|
||||||
coreData.devices[deviceIndex].e +
|
|
||||||
' ' +
|
|
||||||
LL.ENTITIES(shown_data.length)}
|
|
||||||
<IconButton onClick={() => setShowDeviceInfo(true)}>
|
<IconButton onClick={() => setShowDeviceInfo(true)}>
|
||||||
<InfoOutlinedIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
<InfoOutlinedIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton onClick={customize}>
|
|
||||||
<FormatListNumberedIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton onClick={handleDownloadCsv}>
|
<IconButton onClick={handleDownloadCsv}>
|
||||||
<DownloadIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
<DownloadIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -536,7 +511,7 @@ const DashboardDevices: FC = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Grid item zeroMinWidth justifyContent="flex-end">
|
<Grid item zeroMinWidth justifyContent="flex-end">
|
||||||
<IconButton onClick={resetDeviceSelect}>
|
<IconButton onClick={resetDeviceSelect}>
|
||||||
<HighlightOffIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
<CancelIcon color="info" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ import { updateValue } from 'utils';
|
|||||||
|
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
|
|
||||||
|
// const dialogStyle = {
|
||||||
|
// '& .MuiDialog-paper': {
|
||||||
|
// borderRadius: '8px',
|
||||||
|
// borderColor: '#565656',
|
||||||
|
// borderStyle: 'solid',
|
||||||
|
// borderWidth: '1px'
|
||||||
|
// },
|
||||||
|
// backdropFilter: 'blur(1px)'
|
||||||
|
// };
|
||||||
|
|
||||||
type DashboardDevicesDialogProps = {
|
type DashboardDevicesDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -89,16 +99,27 @@ const DashboardDevicesDialog = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showHelperText = (dv: DeviceValue) =>
|
const showHelperText = (dv: DeviceValue) => {
|
||||||
dv.h ? (
|
if (dv.h) {
|
||||||
dv.h
|
return dv.h;
|
||||||
) : dv.l ? (
|
}
|
||||||
dv.l.join(' | ')
|
if (dv.l) {
|
||||||
) : dv.m !== undefined && dv.x !== undefined ? (
|
return '[ ' + dv.l.join(' | ') + ' ]';
|
||||||
<>
|
}
|
||||||
{dv.m} → {dv.x}
|
|
||||||
</>
|
let helperText = '<';
|
||||||
) : undefined;
|
if (dv.s) {
|
||||||
|
helperText += 'n';
|
||||||
|
if (dv.m !== undefined && dv.x !== undefined) {
|
||||||
|
helperText += ' between ' + dv.m + ' and ' + dv.x;
|
||||||
|
} else {
|
||||||
|
helperText += ' , step ' + dv.s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
helperText += 'text';
|
||||||
|
}
|
||||||
|
return helperText + '>';
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog sx={dialogStyle} open={open} onClose={close}>
|
<Dialog sx={dialogStyle} open={open} onClose={close}>
|
||||||
@@ -114,7 +135,7 @@ const DashboardDevicesDialog = ({
|
|||||||
{editItem.l ? (
|
{editItem.l ? (
|
||||||
<TextField
|
<TextField
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(1)}
|
label={LL.VALUE(0)}
|
||||||
value={editItem.v}
|
value={editItem.v}
|
||||||
disabled={!writeable}
|
disabled={!writeable}
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -132,7 +153,7 @@ const DashboardDevicesDialog = ({
|
|||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(1)}
|
label={LL.VALUE(0)}
|
||||||
value={Math.round(editItem.v * 10) / 10}
|
value={Math.round(editItem.v * 10) / 10}
|
||||||
autoFocus
|
autoFocus
|
||||||
disabled={!writeable}
|
disabled={!writeable}
|
||||||
@@ -148,7 +169,7 @@ const DashboardDevicesDialog = ({
|
|||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(1)}
|
label={LL.VALUE(0)}
|
||||||
value={editItem.v}
|
value={editItem.v}
|
||||||
disabled={!writeable}
|
disabled={!writeable}
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -160,7 +181,7 @@ const DashboardDevicesDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
{writeable && (
|
{writeable && (
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<FormHelperText>{showHelperText(editItem)}</FormHelperText>
|
<FormHelperText>format: {showHelperText(editItem)}</FormHelperText>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import DashboardSensorsAnalogDialog from './DashboardSensorsAnalogDialog';
|
|||||||
import DashboardSensorsTemperatureDialog from './DashboardSensorsTemperatureDialog';
|
import DashboardSensorsTemperatureDialog from './DashboardSensorsTemperatureDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
|
|
||||||
import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames, AnalogType } from './types';
|
import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames } from './types';
|
||||||
import { temperatureSensorItemValidation, analogSensorItemValidation } from './validators';
|
import { temperatureSensorItemValidation, analogSensorItemValidation } from './validators';
|
||||||
import type { TemperatureSensor, AnalogSensor } from './types';
|
import type { TemperatureSensor, AnalogSensor } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -38,8 +38,7 @@ const DashboardSensors: FC = () => {
|
|||||||
initialData: {
|
initialData: {
|
||||||
ts: [],
|
ts: [],
|
||||||
as: [],
|
as: [],
|
||||||
analog_enabled: false,
|
analog_enabled: false
|
||||||
platform: 'ESP32'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -392,11 +391,7 @@ const DashboardSensors: FC = () => {
|
|||||||
<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 ? (
|
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
||||||
<Cell stiff>{a.v ? LL.ON() : LL.OFF()}</Cell>
|
|
||||||
) : (
|
|
||||||
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
|
||||||
)}
|
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
</Body>
|
</Body>
|
||||||
@@ -407,22 +402,18 @@ const DashboardSensors: FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SENSOR_DATA()} titleGutter>
|
<SectionContent title={LL.SENSOR_DATA()} titleGutter>
|
||||||
{sensorData.ts.length > 0 && (
|
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
||||||
<>
|
{LL.TEMP_SENSORS()}
|
||||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
</Typography>
|
||||||
{LL.TEMP_SENSORS()}
|
<RenderTemperatureSensors />
|
||||||
</Typography>
|
{selectedTemperatureSensor && (
|
||||||
<RenderTemperatureSensors />
|
<DashboardSensorsTemperatureDialog
|
||||||
{selectedTemperatureSensor && (
|
open={temperatureDialogOpen}
|
||||||
<DashboardSensorsTemperatureDialog
|
onClose={onTemperatureDialogClose}
|
||||||
open={temperatureDialogOpen}
|
onSave={onTemperatureDialogSave}
|
||||||
onClose={onTemperatureDialogClose}
|
selectedItem={selectedTemperatureSensor}
|
||||||
onSave={onTemperatureDialogSave}
|
validator={temperatureSensorItemValidation()}
|
||||||
selectedItem={selectedTemperatureSensor}
|
/>
|
||||||
validator={temperatureSensorItemValidation()}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sensorData?.analog_enabled === true && (
|
{sensorData?.analog_enabled === true && (
|
||||||
@@ -438,7 +429,7 @@ const DashboardSensors: FC = () => {
|
|||||||
onSave={onAnalogDialogSave}
|
onSave={onAnalogDialogSave}
|
||||||
creating={creating}
|
creating={creating}
|
||||||
selectedItem={selectedAnalogSensor}
|
selectedItem={selectedAnalogSensor}
|
||||||
validator={analogSensorItemValidation(sensorData.as, creating, sensorData.platform)}
|
validator={analogSensorItemValidation(sensorData.as, creating)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@@ -451,16 +442,14 @@ const DashboardSensors: FC = () => {
|
|||||||
{LL.REFRESH()}
|
{LL.REFRESH()}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
{sensorData?.analog_enabled === true && (
|
<Button
|
||||||
<Button
|
variant="outlined"
|
||||||
variant="outlined"
|
color="primary"
|
||||||
color="primary"
|
startIcon={<AddCircleOutlineOutlinedIcon />}
|
||||||
startIcon={<AddCircleOutlineOutlinedIcon />}
|
onClick={addAnalogSensor}
|
||||||
onClick={addAnalogSensor}
|
>
|
||||||
>
|
{LL.ADD(0) + ' ' + LL.ANALOG_SENSOR(1)}
|
||||||
{LL.ADD(0) + ' ' + LL.ANALOG_SENSOR(1)}
|
</Button>
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ const DashboardSensorsAnalogDialog = ({
|
|||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
name="g"
|
name="g"
|
||||||
label="GPIO"
|
label="GPIO"
|
||||||
|
disabled={!creating}
|
||||||
value={numberValue(editItem.g)}
|
value={numberValue(editItem.g)}
|
||||||
type="number"
|
type="number"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -123,60 +124,60 @@ const DashboardSensorsAnalogDialog = ({
|
|||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
||||||
<Grid item xs={4}>
|
<>
|
||||||
<TextField name="u" label={LL.UNIT()} value={editItem.u} fullWidth select onChange={updateFormValue}>
|
<Grid item xs={4}>
|
||||||
{DeviceValueUOM_s.map((val, i) => (
|
<TextField name="u" label={LL.UNIT()} value={editItem.u} fullWidth select onChange={updateFormValue}>
|
||||||
<MenuItem key={i} value={i}>
|
{DeviceValueUOM_s.map((val, i) => (
|
||||||
{val}
|
<MenuItem key={i} value={i}>
|
||||||
</MenuItem>
|
{val}
|
||||||
))}
|
</MenuItem>
|
||||||
</TextField>
|
))}
|
||||||
</Grid>
|
</TextField>
|
||||||
)}
|
</Grid>
|
||||||
{editItem.t === AnalogType.ADC && (
|
{editItem.t === AnalogType.ADC && (
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="o"
|
name="o"
|
||||||
label={LL.OFFSET()}
|
label={LL.OFFSET()}
|
||||||
value={numberValue(editItem.o)}
|
value={numberValue(editItem.o)}
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
inputProps={{ min: '0', max: '3300', step: '1' }}
|
inputProps={{ min: '0', max: '3300', step: '1' }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: <InputAdornment position="start">mV</InputAdornment>
|
startAdornment: <InputAdornment position="start">mV</InputAdornment>
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
{editItem.t === AnalogType.COUNTER && (
|
{editItem.t === AnalogType.COUNTER && (
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="o"
|
name="o"
|
||||||
label={LL.STARTVALUE()}
|
label={LL.STARTVALUE()}
|
||||||
value={numberValue(editItem.o)}
|
value={numberValue(editItem.o)}
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
inputProps={{ step: '0.001' }}
|
inputProps={{ step: '0.001' }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
<Grid item xs={4}>
|
||||||
<Grid item xs={4}>
|
<TextField
|
||||||
<TextField
|
name="f"
|
||||||
name="f"
|
label={LL.FACTOR()}
|
||||||
label={LL.FACTOR()}
|
value={numberValue(editItem.f)}
|
||||||
value={numberValue(editItem.f)}
|
fullWidth
|
||||||
fullWidth
|
type="number"
|
||||||
type="number"
|
variant="outlined"
|
||||||
variant="outlined"
|
onChange={updateFormValue}
|
||||||
onChange={updateFormValue}
|
inputProps={{ step: '0.001' }}
|
||||||
inputProps={{ step: '0.001' }}
|
/>
|
||||||
/>
|
</Grid>
|
||||||
</Grid>
|
</>
|
||||||
)}
|
)}
|
||||||
{editItem.t === AnalogType.DIGITAL_OUT && (editItem.g === 25 || editItem.g === 26) && (
|
{editItem.t === AnalogType.DIGITAL_OUT && (editItem.g === 25 || editItem.g === 26) && (
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
@@ -193,55 +194,20 @@ const DashboardSensorsAnalogDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
{editItem.t === AnalogType.DIGITAL_OUT && editItem.g !== 25 && editItem.g !== 26 && (
|
{editItem.t === AnalogType.DIGITAL_OUT && editItem.g !== 25 && editItem.g !== 26 && (
|
||||||
<>
|
<Grid item xs={4}>
|
||||||
<Grid item xs={4}>
|
<TextField
|
||||||
<TextField
|
name="o"
|
||||||
name="o"
|
label={LL.VALUE(0)}
|
||||||
label={LL.VALUE(0)}
|
value={numberValue(editItem.o)}
|
||||||
value={numberValue(editItem.o)}
|
fullWidth
|
||||||
fullWidth
|
type="number"
|
||||||
select
|
variant="outlined"
|
||||||
variant="outlined"
|
onChange={updateFormValue}
|
||||||
onChange={updateFormValue}
|
inputProps={{ min: '0', max: '1', step: '1' }}
|
||||||
>
|
/>
|
||||||
<MenuItem value={0}>{LL.OFF()}</MenuItem>
|
</Grid>
|
||||||
<MenuItem value={1}>{LL.ON()}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<TextField
|
|
||||||
name="f"
|
|
||||||
label={LL.POLARITY()}
|
|
||||||
value={editItem.f}
|
|
||||||
fullWidth
|
|
||||||
select
|
|
||||||
onChange={updateFormValue}
|
|
||||||
>
|
|
||||||
<MenuItem value={1}>{LL.ACTIVEHIGH()}</MenuItem>
|
|
||||||
<MenuItem value={-1}>{LL.ACTIVELOW()}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<TextField
|
|
||||||
name="u"
|
|
||||||
label={LL.STARTVALUE()}
|
|
||||||
value={editItem.u}
|
|
||||||
fullWidth
|
|
||||||
select
|
|
||||||
onChange={updateFormValue}
|
|
||||||
>
|
|
||||||
<MenuItem value={0}>{LL.UNCHANGED()}</MenuItem>
|
|
||||||
<MenuItem value={1}>
|
|
||||||
{LL.ALWAYS()} {LL.OFF()}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={2}>
|
|
||||||
{LL.ALWAYS()} {LL.ON()}
|
|
||||||
</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{(editItem.t === AnalogType.PWM_0 || editItem.t === AnalogType.PWM_1 || editItem.t === AnalogType.PWM_2) && (
|
{editItem.t >= AnalogType.PWM_0 && (
|
||||||
<>
|
<>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { AiOutlineControl, AiOutlineGateway, AiOutlineAlert } from 'react-icons/ai';
|
import { AiOutlineControl, AiOutlineGateway, AiOutlineAlert, AiOutlineChrome } from 'react-icons/ai';
|
||||||
import { CgSmartHomeBoiler } from 'react-icons/cg';
|
import { CgSmartHomeBoiler } from 'react-icons/cg';
|
||||||
|
|
||||||
import { FaSolarPanel } from 'react-icons/fa';
|
import { FaSolarPanel } from 'react-icons/fa';
|
||||||
import { GiHeatHaze } from 'react-icons/gi';
|
import { GiHeatHaze } from 'react-icons/gi';
|
||||||
import { MdThermostatAuto, MdOutlineSensors, MdOutlineExtension, MdOutlineDevices } from 'react-icons/md';
|
import { MdThermostatAuto, MdOutlineSensors, MdOutlineExtension } from 'react-icons/md';
|
||||||
import { TiFlowSwitch } from 'react-icons/ti';
|
import { TiFlowSwitch } from 'react-icons/ti';
|
||||||
import { VscVmConnect } from 'react-icons/vsc';
|
import { VscVmConnect } from 'react-icons/vsc';
|
||||||
import { DeviceType } from './types';
|
import { DeviceType } from './types';
|
||||||
@@ -38,8 +38,8 @@ const DeviceIcon: FC<DeviceIconProps> = ({ type_id }) => {
|
|||||||
return <VscVmConnect />;
|
return <VscVmConnect />;
|
||||||
case DeviceType.ALERT:
|
case DeviceType.ALERT:
|
||||||
return <AiOutlineAlert />;
|
return <AiOutlineAlert />;
|
||||||
case DeviceType.EXTENSION:
|
case DeviceType.PUMP:
|
||||||
return <MdOutlineDevices />;
|
return <AiOutlineChrome />;
|
||||||
case DeviceType.CUSTOM:
|
case DeviceType.CUSTOM:
|
||||||
return <MdOutlineExtension />;
|
return <MdOutlineExtension />;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,121 +1,28 @@
|
|||||||
import CommentIcon from '@mui/icons-material/CommentTwoTone';
|
import { Tab } from '@mui/material';
|
||||||
import EastIcon from '@mui/icons-material/East';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import HelpInformation from './HelpInformation';
|
||||||
import GitHubIcon from '@mui/icons-material/GitHub';
|
|
||||||
import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
|
||||||
import { Box, List, ListItem, ListItemAvatar, ListItemText, Link, Typography, Button } from '@mui/material';
|
|
||||||
import { useRequest } from 'alova';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { SectionContent, useLayoutTitle } from 'components';
|
|
||||||
|
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import * as EMSESP from 'project/api';
|
|
||||||
|
|
||||||
const Help: FC = () => {
|
const Help: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
useLayoutTitle(LL.HELP_OF(''));
|
useLayoutTitle(LL.HELP_OF(''));
|
||||||
|
|
||||||
const { send: getSystemAPI, onSuccess: onGetAPI } = useRequest((data) => EMSESP.APIcall('system', data), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
onGetAPI((event) => {
|
|
||||||
const anchor = document.createElement('a');
|
|
||||||
anchor.href = URL.createObjectURL(
|
|
||||||
new Blob([JSON.stringify(event.data, null, 2)], {
|
|
||||||
type: 'text/plain'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
anchor.download = 'emsesp_' + event.sendArgs[0].entity + '.txt';
|
|
||||||
anchor.click();
|
|
||||||
URL.revokeObjectURL(anchor.href);
|
|
||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
|
||||||
});
|
|
||||||
|
|
||||||
const callSystemAPI = async (entity: string) => {
|
|
||||||
await getSystemAPI({ entity, id: 0 }).catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SUPPORT_INFORMATION(0)} titleGutter>
|
<>
|
||||||
<List>
|
<RouterTabs value={routerTab}>
|
||||||
<ListItem>
|
<Tab value="information" label={LL.HELP_OF('EMS-ESP')} />
|
||||||
<ListItemAvatar>
|
</RouterTabs>
|
||||||
<MenuBookIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
<Routes>
|
||||||
</ListItemAvatar>
|
<Route path="information" element={<HelpInformation />} />
|
||||||
<ListItemText>
|
<Route path="/*" element={<Navigate replace to="information" />} />
|
||||||
{LL.HELP_INFORMATION_1()}
|
</Routes>
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
</>
|
||||||
|
|
||||||
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
|
||||||
{LL.CLICK_HERE()}
|
|
||||||
</Link>
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<CommentIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText>
|
|
||||||
{LL.HELP_INFORMATION_2()}
|
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
|
||||||
|
|
||||||
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
|
||||||
{LL.CLICK_HERE()}
|
|
||||||
</Link>
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<GitHubIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText>
|
|
||||||
{LL.HELP_INFORMATION_3()}
|
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
|
||||||
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
|
||||||
{LL.CLICK_HERE()}
|
|
||||||
</Link>
|
|
||||||
<br />
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
|
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography mb={1} variant="body2">
|
|
||||||
{LL.HELP_INFORMATION_4()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callSystemAPI('info')}>
|
|
||||||
{LL.SUPPORT_INFORMATION(0)}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
sx={{ ml: 2 }}
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => callSystemAPI('allvalues')}
|
|
||||||
>
|
|
||||||
All Values
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Box border={1} p={1} mt={4} color="orange">
|
|
||||||
<Typography align="center" variant="subtitle1" color="orange">
|
|
||||||
<b>{LL.HELP_INFORMATION_5()}</b>
|
|
||||||
</Typography>
|
|
||||||
<Typography align="center">
|
|
||||||
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
|
||||||
{'github.com/emsesp/EMS-ESP32'}
|
|
||||||
</Link>
|
|
||||||
</Typography>
|
|
||||||
<Typography color="white" variant="subtitle2" align="center">
|
|
||||||
@proddy @MichaelDvP
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</SectionContent>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
118
interface/src/project/HelpInformation.tsx
Normal file
118
interface/src/project/HelpInformation.tsx
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import CommentIcon from '@mui/icons-material/CommentTwoTone';
|
||||||
|
import EastIcon from '@mui/icons-material/East';
|
||||||
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
|
import GitHubIcon from '@mui/icons-material/GitHub';
|
||||||
|
import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
||||||
|
import { Typography, Button, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@mui/material';
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import * as EMSESP from './api';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import { SectionContent } from 'components';
|
||||||
|
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
|
const HelpInformation: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
const { send: API, onSuccess: onSuccessAPI } = useRequest((data) => EMSESP.API(data), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
onSuccessAPI((event) => {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
const filename = 'emsesp_info.txt';
|
||||||
|
a.href = URL.createObjectURL(
|
||||||
|
new Blob([JSON.stringify(event.data, null, 2)], {
|
||||||
|
type: 'text/plain'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
a.setAttribute('download', filename);
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
|
});
|
||||||
|
|
||||||
|
const callAPI = async () => {
|
||||||
|
await API({ device: 'system', entity: 'info', id: 0 }).catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionContent title={LL.SUPPORT_INFORMATION()} titleGutter>
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<MenuBookIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText>
|
||||||
|
{LL.HELP_INFORMATION_1()}
|
||||||
|
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
|
||||||
|
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
||||||
|
{LL.CLICK_HERE()}
|
||||||
|
</Link>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<CommentIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText>
|
||||||
|
{LL.HELP_INFORMATION_2()}
|
||||||
|
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
|
||||||
|
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
||||||
|
{LL.CLICK_HERE()}
|
||||||
|
</Link>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<GitHubIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText>
|
||||||
|
{LL.HELP_INFORMATION_3()}
|
||||||
|
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
||||||
|
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
||||||
|
{LL.CLICK_HERE()}
|
||||||
|
</Link>
|
||||||
|
<br />
|
||||||
|
<i>({LL.HELP_INFORMATION_4()}</i>
|
||||||
|
<Button
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => callAPI()}
|
||||||
|
>
|
||||||
|
{LL.SUPPORT_INFO()}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Box border={1} p={1} mt={4} color="orange">
|
||||||
|
<Typography align="center" variant="subtitle1" color="orange">
|
||||||
|
<b>{LL.HELP_INFORMATION_5()}</b>
|
||||||
|
</Typography>
|
||||||
|
<Typography align="center">
|
||||||
|
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
||||||
|
{'github.com/emsesp/EMS-ESP32'}
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
<Typography color="white" align="center">
|
||||||
|
@proddy @MichaelDvP
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</SectionContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HelpInformation;
|
||||||
@@ -18,17 +18,17 @@ const Settings: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/settings/application" label={LL.APPLICATION_SETTINGS()} />
|
<Tab value="application" label={LL.APPLICATION_SETTINGS()} />
|
||||||
<Tab value="/settings/customization" label={LL.CUSTOMIZATIONS()} />
|
<Tab value="customization" label={LL.CUSTOMIZATIONS()} />
|
||||||
<Tab value="/settings/scheduler" label={LL.SCHEDULER()} />
|
<Tab value="scheduler" label={LL.SCHEDULER()} />
|
||||||
<Tab value="/settings/customentities" label={LL.CUSTOM_ENTITIES(0)} />
|
<Tab value="customentities" label={LL.CUSTOM_ENTITIES(0)} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="application" element={<SettingsApplication />} />
|
<Route path="application" element={<SettingsApplication />} />
|
||||||
<Route path="customization" element={<SettingsCustomization />} />
|
<Route path="customization" element={<SettingsCustomization />} />
|
||||||
<Route path="scheduler" element={<SettingsScheduler />} />
|
<Route path="scheduler" element={<SettingsScheduler />} />
|
||||||
<Route path="customentities" element={<SettingsEntities />} />
|
<Route path="customentities" element={<SettingsEntities />} />
|
||||||
<Route path="*" element={<Navigate replace to="/settings/application" />} />
|
<Route path="/*" element={<Navigate replace to="application" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -384,7 +384,6 @@ const SettingsApplication: FC = () => {
|
|||||||
<MenuItem value="nl">Nederlands (NL)</MenuItem>
|
<MenuItem value="nl">Nederlands (NL)</MenuItem>
|
||||||
<MenuItem value="no">Norsk (NO)</MenuItem>
|
<MenuItem value="no">Norsk (NO)</MenuItem>
|
||||||
<MenuItem value="pl">Polski (PL)</MenuItem>
|
<MenuItem value="pl">Polski (PL)</MenuItem>
|
||||||
<MenuItem value="sk">Slovenčina (SK)</MenuItem>
|
|
||||||
<MenuItem value="sv">Svenska (SV)</MenuItem>
|
<MenuItem value="sv">Svenska (SV)</MenuItem>
|
||||||
<MenuItem value="tr">Türk (TR)</MenuItem>
|
<MenuItem value="tr">Türk (TR)</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
@@ -426,11 +425,6 @@ const SettingsApplication: FC = () => {
|
|||||||
label={LL.UNDERCLOCK_CPU()}
|
label={LL.UNDERCLOCK_CPU()}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
/>
|
/>
|
||||||
<BlockFormControlLabel
|
|
||||||
control={<Checkbox checked={data.boiler_heatingoff} onChange={updateFormValue} name="boiler_heatingoff" />}
|
|
||||||
label={LL.HEATINGOFF()}
|
|
||||||
disabled={saving}
|
|
||||||
/>
|
|
||||||
<Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
<Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}
|
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}
|
||||||
@@ -645,7 +639,7 @@ const SettingsApplication: FC = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
{restartNeeded && (
|
{restartNeeded && (
|
||||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
|
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
||||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||||
{LL.RESTART()}
|
{LL.RESTART()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-li
|
|||||||
import { useTheme } from '@table-library/react-table-library/theme';
|
import { useTheme } from '@table-library/react-table-library/theme';
|
||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useBlocker, useLocation } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import EntityMaskToggle from './EntityMaskToggle';
|
import EntityMaskToggle from './EntityMaskToggle';
|
||||||
@@ -52,26 +52,20 @@ const SettingsCustomization: FC = () => {
|
|||||||
const [restarting, setRestarting] = useState<boolean>(false);
|
const [restarting, setRestarting] = useState<boolean>(false);
|
||||||
const [restartNeeded, setRestartNeeded] = useState<boolean>(false);
|
const [restartNeeded, setRestartNeeded] = useState<boolean>(false);
|
||||||
const [deviceEntities, setDeviceEntities] = useState<DeviceEntity[]>([]);
|
const [deviceEntities, setDeviceEntities] = useState<DeviceEntity[]>([]);
|
||||||
|
const [selectedDevice, setSelectedDevice] = useState<number>(-1);
|
||||||
const [confirmReset, setConfirmReset] = useState<boolean>(false);
|
const [confirmReset, setConfirmReset] = useState<boolean>(false);
|
||||||
const [selectedFilters, setSelectedFilters] = useState<number>(0);
|
const [selectedFilters, setSelectedFilters] = useState<number>(0);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [selectedDeviceEntity, setSelectedDeviceEntity] = useState<DeviceEntity>();
|
const [selectedDeviceEntity, setSelectedDeviceEntity] = useState<DeviceEntity>();
|
||||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
// fetch devices first
|
|
||||||
const { data: devices } = useRequest(EMSESP.readDevices);
|
|
||||||
|
|
||||||
// const { state } = useLocation();
|
|
||||||
const [selectedDevice, setSelectedDevice] = useState<number>(useLocation().state || -1);
|
|
||||||
const [selectedDeviceName, setSelectedDeviceName] = useState<string>('');
|
|
||||||
|
|
||||||
const { send: resetCustomizations } = useRequest(EMSESP.resetCustomizations(), {
|
const { send: resetCustomizations } = useRequest(EMSESP.resetCustomizations(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: writeCustomizationEntities } = useRequest((data) => EMSESP.writeCustomizationEntities(data), {
|
const { data: devices } = useRequest(EMSESP.readDevices);
|
||||||
immediate: false
|
|
||||||
});
|
const { send: writeCustomEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false });
|
||||||
|
|
||||||
const { send: readDeviceEntities, onSuccess: onSuccess } = useRequest((data) => EMSESP.readDeviceEntities(data), {
|
const { send: readDeviceEntities, onSuccess: onSuccess } = useRequest((data) => EMSESP.readDeviceEntities(data), {
|
||||||
initialData: [],
|
initialData: [],
|
||||||
@@ -92,7 +86,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
|
|
||||||
const entities_theme = useTheme({
|
const entities_theme = useTheme({
|
||||||
Table: `
|
Table: `
|
||||||
--data-table-library_grid-template-columns: 156px repeat(1, minmax(80px, 1fr)) 45px minmax(45px, auto) minmax(120px, auto);
|
--data-table-library_grid-template-columns: 150px repeat(1, minmax(80px, 1fr)) 45px minmax(45px, auto) minmax(120px, auto);
|
||||||
`,
|
`,
|
||||||
BaseRow: `
|
BaseRow: `
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -180,22 +174,6 @@ const SettingsCustomization: FC = () => {
|
|||||||
}
|
}
|
||||||
}, [deviceEntities]);
|
}, [deviceEntities]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (devices && selectedDevice !== -1) {
|
|
||||||
void readDeviceEntities(selectedDevice);
|
|
||||||
const id = devices.devices.findIndex((d) => d.i === selectedDevice);
|
|
||||||
if (id === -1) {
|
|
||||||
setSelectedDevice(-1);
|
|
||||||
setSelectedDeviceName('');
|
|
||||||
} else {
|
|
||||||
setSelectedDeviceName(devices.devices[id].tn || '');
|
|
||||||
setNumChanges(0);
|
|
||||||
setRestartNeeded(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [devices, selectedDevice]);
|
|
||||||
|
|
||||||
const restart = async () => {
|
const restart = async () => {
|
||||||
await restartCommand().catch((error) => {
|
await restartCommand().catch((error) => {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
@@ -214,9 +192,17 @@ const SettingsCustomization: FC = () => {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatName = (de: DeviceEntity, withShortname: boolean) =>
|
function formatName(de: DeviceEntity) {
|
||||||
(de.n && de.n[0] === '!' ? LL.COMMAND(1) + ': ' + de.n.slice(1) : de.cn && de.cn !== '' ? de.cn : de.n) +
|
return (
|
||||||
(withShortname ? ' ' + de.id : '');
|
<>
|
||||||
|
{de.n && (de.n[0] === '!' ? LL.COMMAND(1) + ': ' + de.n.slice(1) : de.cn && de.cn !== '' ? de.cn : de.n) + ' '}(
|
||||||
|
<Link target="_blank" href={APIURL + devices?.devices[selectedDevice].tn + '/' + de.id}>
|
||||||
|
{de.id}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const getMaskNumber = (newMask: string[]) => {
|
const getMaskNumber = (newMask: string[]) => {
|
||||||
let new_mask = 0;
|
let new_mask = 0;
|
||||||
@@ -246,13 +232,10 @@ const SettingsCustomization: FC = () => {
|
|||||||
return new_masks;
|
return new_masks;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filter_entity = (de: DeviceEntity) =>
|
|
||||||
(de.m & selectedFilters || !selectedFilters) && formatName(de, true).includes(search.toLocaleLowerCase());
|
|
||||||
|
|
||||||
const maskDisabled = (set: boolean) => {
|
const maskDisabled = (set: boolean) => {
|
||||||
setDeviceEntities(
|
setDeviceEntities(
|
||||||
deviceEntities.map(function (de) {
|
deviceEntities.map(function (de) {
|
||||||
if (filter_entity(de)) {
|
if ((de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())) {
|
||||||
return {
|
return {
|
||||||
...de,
|
...de,
|
||||||
m: set
|
m: set
|
||||||
@@ -266,6 +249,16 @@ const SettingsCustomization: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeSelectedDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (devices) {
|
||||||
|
const selected_device = parseInt(event.target.value, 10);
|
||||||
|
setSelectedDevice(selected_device);
|
||||||
|
setNumChanges(0);
|
||||||
|
void readDeviceEntities(devices?.devices[selected_device].i);
|
||||||
|
setRestartNeeded(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const resetCustomization = async () => {
|
const resetCustomization = async () => {
|
||||||
try {
|
try {
|
||||||
await resetCustomizations();
|
await resetCustomizations();
|
||||||
@@ -324,21 +317,30 @@ const SettingsCustomization: FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeCustomizationEntities({ id: selectedDevice, entity_ids: masked_entities }).catch((error) => {
|
await writeCustomEntities({ id: devices?.devices[selectedDevice].i, entity_ids: masked_entities }).catch(
|
||||||
if (error.message === 'Reboot required') {
|
(error) => {
|
||||||
setRestartNeeded(true);
|
if (error.message === 'Reboot required') {
|
||||||
} else {
|
setRestartNeeded(true);
|
||||||
toast.error(error.message);
|
} else {
|
||||||
|
toast.error(error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
setOriginalSettings(deviceEntities);
|
setOriginalSettings(deviceEntities);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderDeviceList = () => (
|
const renderDeviceList = () => (
|
||||||
<>
|
<>
|
||||||
<Box mb={1} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
<Typography variant="body2">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
||||||
|
<Typography variant="body2" mt={1}>
|
||||||
|
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
||||||
|
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
||||||
|
<OptionIcon type="api_mqtt_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_4()}
|
||||||
|
<OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()}
|
||||||
|
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<TextField
|
<TextField
|
||||||
name="device"
|
name="device"
|
||||||
@@ -347,15 +349,15 @@ const SettingsCustomization: FC = () => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
value={selectedDevice}
|
value={selectedDevice}
|
||||||
disabled={numChanges !== 0}
|
disabled={numChanges !== 0}
|
||||||
onChange={(e) => setSelectedDevice(parseInt(e.target.value))}
|
onChange={changeSelectedDevice}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
select
|
select
|
||||||
>
|
>
|
||||||
<MenuItem disabled key={-1} value={-1}>
|
<MenuItem disabled key={0} value={-1}>
|
||||||
{LL.SELECT_DEVICE()}...
|
{LL.SELECT_DEVICE()}...
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{devices.devices.map((device: DeviceShort) => (
|
{devices.devices.map((device: DeviceShort, index) => (
|
||||||
<MenuItem key={device.i} value={device.i}>
|
<MenuItem key={index} value={index}>
|
||||||
{device.s}
|
{device.s}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
@@ -364,19 +366,16 @@ const SettingsCustomization: FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const renderDeviceData = () => {
|
const renderDeviceData = () => {
|
||||||
const shown_data = deviceEntities.filter((de) => filter_entity(de));
|
if (deviceEntities.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shown_data = deviceEntities.filter(
|
||||||
|
(de) => (de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography variant="body2" mt={1}>
|
|
||||||
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
|
||||||
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
|
||||||
<OptionIcon type="api_mqtt_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_4()}
|
|
||||||
<OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()}
|
|
||||||
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Grid container mb={1} mt={0} spacing={1} direction="row" justifyContent="flex-start" alignItems="center">
|
<Grid container mb={1} mt={0} spacing={1} direction="row" justifyContent="flex-start" alignItems="center">
|
||||||
<Grid item xs={2}>
|
<Grid item xs={2}>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -449,7 +448,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography variant="subtitle2" color="primary">
|
<Typography variant="subtitle2" color="primary">
|
||||||
{LL.SHOWING()} {shown_data.length}/{deviceEntities.length} {LL.ENTITIES(deviceEntities.length)}
|
{LL.SHOWING()} {shown_data.length}/{deviceEntities.length}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -471,13 +470,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
<EntityMaskToggle onUpdate={updateDeviceEntity} de={de} />
|
<EntityMaskToggle onUpdate={updateDeviceEntity} de={de} />
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>
|
<Cell>{formatName(de)}</Cell>
|
||||||
{formatName(de, false)} (
|
|
||||||
<Link target="_blank" href={APIURL + selectedDeviceName + '/' + de.id}>
|
|
||||||
{de.id}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
</Cell>
|
|
||||||
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.mi)}</Cell>
|
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.mi)}</Cell>
|
||||||
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.ma)}</Cell>
|
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.ma)}</Cell>
|
||||||
<Cell>{formatValue(de.v)}</Cell>
|
<Cell>{formatValue(de.v)}</Cell>
|
||||||
@@ -512,9 +505,9 @@ const SettingsCustomization: FC = () => {
|
|||||||
{LL.DEVICE_ENTITIES()}
|
{LL.DEVICE_ENTITIES()}
|
||||||
</Typography>
|
</Typography>
|
||||||
{devices && renderDeviceList()}
|
{devices && renderDeviceList()}
|
||||||
{deviceEntities && renderDeviceData()}
|
{renderDeviceData()}
|
||||||
{restartNeeded && (
|
{restartNeeded && (
|
||||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
|
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
||||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||||
{LL.RESTART()}
|
{LL.RESTART()}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -529,7 +522,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={() => devices && readDeviceEntities(selectedDevice)}
|
onClick={() => devices && readDeviceEntities(devices.devices[selectedDevice].i)}
|
||||||
>
|
>
|
||||||
{LL.CANCEL()}
|
{LL.CANCEL()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -68,34 +67,15 @@ const SettingsCustomizationDialog = ({ open, onClose, onSave, selectedItem }: Se
|
|||||||
<Dialog sx={dialogStyle} open={open} onClose={close}>
|
<Dialog sx={dialogStyle} open={open} onClose={close}>
|
||||||
<DialogTitle>{LL.EDIT() + ' ' + LL.ENTITY()}</DialogTitle>
|
<DialogTitle>{LL.EDIT() + ' ' + LL.ENTITY()}</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Grid container direction="row">
|
<Box color="warning.main">
|
||||||
<Typography variant="body2" color="warning.main">
|
|
||||||
{LL.ID_OF(LL.ENTITY())}:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2">{editItem.id}</Typography>
|
<Typography variant="body2">{editItem.id}</Typography>
|
||||||
</Grid>
|
</Box>
|
||||||
|
<Box color="warning.main" mt={1} mb={2}>
|
||||||
<Grid container direction="row">
|
|
||||||
<Typography variant="body2" color="warning.main">
|
|
||||||
{LL.DEFAULT(1) + ' ' + LL.ENTITY_NAME(1)}:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2">{editItem.n}</Typography>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid container direction="row">
|
|
||||||
<Typography variant="body2" color="warning.main">
|
|
||||||
{LL.WRITEABLE()}:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{editItem.w ? (
|
{LL.DEFAULT(1) + ' ' + LL.ENTITY_NAME(1)}: {editItem.n}
|
||||||
<DoneIcon color="success" sx={{ fontSize: 16 }} />
|
|
||||||
) : (
|
|
||||||
<CloseIcon color="error" sx={{ fontSize: 16 }} />
|
|
||||||
)}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Box>
|
||||||
|
<Box mb={3}>
|
||||||
<Box mt={1} mb={2}>
|
|
||||||
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
|
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
|
||||||
</Box>
|
</Box>
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import { useTheme } from '@table-library/react-table-library/theme';
|
|||||||
// eslint-disable-next-line import/named
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import SettingsEntitiesDialog from './SettingsEntitiesDialog';
|
import SettingsEntitiesDialog from './SettingsEntitiesDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
import { DeviceValueUOM_s } from './types';
|
||||||
import { entityItemValidation } from './validators';
|
import { entityItemValidation } from './validators';
|
||||||
import type { EntityItem } from './types';
|
import type { EntityItem } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -33,12 +33,12 @@ const SettingsEntities: FC = () => {
|
|||||||
data: entities,
|
data: entities,
|
||||||
send: fetchEntities,
|
send: fetchEntities,
|
||||||
error
|
error
|
||||||
} = useRequest(EMSESP.readCustomEntities, {
|
} = useRequest(EMSESP.readEntities, {
|
||||||
initialData: [],
|
initialData: [],
|
||||||
force: true
|
force: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: writeEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false });
|
const { send: writeEntities } = useRequest((data) => EMSESP.writeEntities(data), { immediate: false });
|
||||||
|
|
||||||
function hasEntityChanged(ei: EntityItem) {
|
function hasEntityChanged(ei: EntityItem) {
|
||||||
return (
|
return (
|
||||||
@@ -57,7 +57,7 @@ const SettingsEntities: FC = () => {
|
|||||||
|
|
||||||
const entity_theme = useTheme({
|
const entity_theme = useTheme({
|
||||||
Table: `
|
Table: `
|
||||||
--data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px 90px;
|
--data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px;
|
||||||
`,
|
`,
|
||||||
BaseRow: `
|
BaseRow: `
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -81,9 +81,6 @@ const SettingsEntities: FC = () => {
|
|||||||
&:nth-of-type(5) {
|
&:nth-of-type(5) {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
&:nth-of-type(6) {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
HeaderRow: `
|
HeaderRow: `
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -189,8 +186,8 @@ const SettingsEntities: FC = () => {
|
|||||||
return value === undefined || uom === undefined
|
return value === undefined || uom === undefined
|
||||||
? ''
|
? ''
|
||||||
: typeof value === 'number'
|
: typeof value === 'number'
|
||||||
? new Intl.NumberFormat().format(value) + (uom === 0 ? '' : ' ' + DeviceValueUOM_s[uom])
|
? new Intl.NumberFormat().format(value) + (uom === 0 ? '' : ' ' + DeviceValueUOM_s[uom])
|
||||||
: value;
|
: value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHex(value: number, digit: number) {
|
function showHex(value: number, digit: number) {
|
||||||
@@ -211,9 +208,8 @@ const SettingsEntities: FC = () => {
|
|||||||
<HeaderCell>{LL.NAME(0)}</HeaderCell>
|
<HeaderCell>{LL.NAME(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
|
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
|
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.OFFSET()}</HeaderCell>
|
<HeaderCell stiff>Offset</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VALUE(1) + ' ' + LL.TYPE(1)}</HeaderCell>
|
<HeaderCell stiff>{LL.VALUE(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
|
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
</Header>
|
</Header>
|
||||||
<Body>
|
<Body>
|
||||||
@@ -223,7 +219,6 @@ const SettingsEntities: FC = () => {
|
|||||||
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
|
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
|
||||||
<Cell>{showHex(ei.type_id as number, 3)}</Cell>
|
<Cell>{showHex(ei.type_id as number, 3)}</Cell>
|
||||||
<Cell>{ei.offset}</Cell>
|
<Cell>{ei.offset}</Cell>
|
||||||
<Cell>{DeviceValueTypeNames[ei.value_type]}</Cell>
|
|
||||||
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ const SettingsEntitiesDialog = ({
|
|||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
name="offset"
|
name="offset"
|
||||||
label={LL.OFFSET()}
|
label="Offset"
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
@@ -159,7 +159,7 @@ const SettingsEntitiesDialog = ({
|
|||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="value_type"
|
name="value_type"
|
||||||
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
|
label="Value Type"
|
||||||
value={editItem.value_type}
|
value={editItem.value_type}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import CircleIcon from '@mui/icons-material/Circle';
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
|
|
||||||
import { Box, Typography, Divider, Stack, Button } from '@mui/material';
|
import { Box, Typography, Divider, Stack, Button } from '@mui/material';
|
||||||
@@ -9,7 +9,7 @@ import { useTheme } from '@table-library/react-table-library/theme';
|
|||||||
// eslint-disable-next-line import/named
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import SettingsSchedulerDialog from './SettingsSchedulerDialog';
|
import SettingsSchedulerDialog from './SettingsSchedulerDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
@@ -208,7 +208,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
<HeaderCell stiff>{LL.SCHEDULE(0)}</HeaderCell>
|
<HeaderCell stiff>{LL.SCHEDULE(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.TIME(0)}</HeaderCell>
|
<HeaderCell stiff>{LL.TIME(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.COMMAND(0)}</HeaderCell>
|
<HeaderCell stiff>{LL.COMMAND(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
|
<HeaderCell stiff>{LL.VALUE(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.NAME(0)}</HeaderCell>
|
<HeaderCell stiff>{LL.NAME(0)}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
</Header>
|
</Header>
|
||||||
@@ -216,11 +216,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
{tableList.map((si: ScheduleItem) => (
|
{tableList.map((si: ScheduleItem) => (
|
||||||
<Row key={si.id} item={si} onClick={() => editScheduleItem(si)}>
|
<Row key={si.id} item={si} onClick={() => editScheduleItem(si)}>
|
||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
{si.active ? (
|
{si.active && <CheckCircleIcon sx={{ color: '#79D200', fontSize: 16, verticalAlign: 'middle' }} />}
|
||||||
<CircleIcon color="success" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
|
|
||||||
) : (
|
|
||||||
<CircleIcon color="error" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
|
|
||||||
)}
|
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
<Stack spacing={1} direction="row">
|
<Stack spacing={1} direction="row">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||||
|
|
||||||
@@ -183,6 +184,11 @@ const SettingsSchedulerDialog = ({
|
|||||||
control={<Checkbox checked={editItem.active} onChange={updateFormValue} name="active" />}
|
control={<Checkbox checked={editItem.active} onChange={updateFormValue} name="active" />}
|
||||||
label={LL.ACTIVE()}
|
label={LL.ACTIVE()}
|
||||||
/>
|
/>
|
||||||
|
{editItem.active && (
|
||||||
|
<Grid item sx={{ mt: 1 }}>
|
||||||
|
<CheckCircleIcon sx={{ color: '#79D200', fontSize: 16, verticalAlign: 'middle' }} />
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -210,7 +216,7 @@ const SettingsSchedulerDialog = ({
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
name="value"
|
name="value"
|
||||||
label={LL.VALUE(0)}
|
label={LL.VALUE(1)}
|
||||||
multiline
|
multiline
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type {
|
import type {
|
||||||
APIdata,
|
APIcall,
|
||||||
Settings,
|
Settings,
|
||||||
Status,
|
Status,
|
||||||
CoreData,
|
CoreData,
|
||||||
@@ -19,8 +19,7 @@ import { alovaInstance } from 'api/endpoints';
|
|||||||
export const readCoreData = () => alovaInstance.Get<CoreData>(`/rest/coreData`);
|
export const readCoreData = () => alovaInstance.Get<CoreData>(`/rest/coreData`);
|
||||||
export const readDeviceData = (id: number) =>
|
export const readDeviceData = (id: number) =>
|
||||||
alovaInstance.Get<DeviceData>('/rest/deviceData', {
|
alovaInstance.Get<DeviceData>('/rest/deviceData', {
|
||||||
// alovaInstance.Get<DeviceData>(`/rest/deviceData/${id}`, {
|
params: { id },
|
||||||
params: { id }, // TODO replace params later
|
|
||||||
responseType: 'arraybuffer' // uses msgpack
|
responseType: 'arraybuffer' // uses msgpack
|
||||||
});
|
});
|
||||||
export const writeDeviceValue = (data: any) => alovaInstance.Post('/rest/writeDeviceValue', data);
|
export const writeDeviceValue = (data: any) => alovaInstance.Post('/rest/writeDeviceValue', data);
|
||||||
@@ -44,7 +43,7 @@ export const readStatus = () => alovaInstance.Get<Status>('/rest/status');
|
|||||||
export const scanDevices = () => alovaInstance.Post('/rest/scanDevices');
|
export const scanDevices = () => alovaInstance.Post('/rest/scanDevices');
|
||||||
|
|
||||||
// HelpInformation
|
// HelpInformation
|
||||||
export const APIcall = (device: string, apiData: APIdata) => alovaInstance.Post(`/api/${device}`, apiData);
|
export const API = (apiCall: APIcall) => alovaInstance.Post('/api', apiCall);
|
||||||
|
|
||||||
// UploadFileForm
|
// UploadFileForm
|
||||||
export const getSettings = () => alovaInstance.Get('/rest/getSettings');
|
export const getSettings = () => alovaInstance.Get('/rest/getSettings');
|
||||||
@@ -54,9 +53,8 @@ export const getSchedule = () => alovaInstance.Get('/rest/getSchedule');
|
|||||||
|
|
||||||
// SettingsCustomization
|
// SettingsCustomization
|
||||||
export const readDeviceEntities = (id: number) =>
|
export const readDeviceEntities = (id: number) =>
|
||||||
// alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities/${id}`, {
|
alovaInstance.Get<DeviceEntity[]>('/rest/deviceEntities', {
|
||||||
alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
|
params: { id },
|
||||||
params: { id }, // TODO replace params later
|
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
transformData(data: any) {
|
transformData(data: any) {
|
||||||
return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma }));
|
return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma }));
|
||||||
@@ -64,7 +62,7 @@ export const readDeviceEntities = (id: number) =>
|
|||||||
});
|
});
|
||||||
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
|
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
|
||||||
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
|
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
|
||||||
export const writeCustomizationEntities = (data: any) => alovaInstance.Post('/rest/customizationEntities', data);
|
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);
|
||||||
|
|
||||||
// SettingsScheduler
|
// SettingsScheduler
|
||||||
export const readSchedule = () =>
|
export const readSchedule = () =>
|
||||||
@@ -87,8 +85,8 @@ export const readSchedule = () =>
|
|||||||
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
||||||
|
|
||||||
// SettingsEntities
|
// SettingsEntities
|
||||||
export const readCustomEntities = () =>
|
export const readEntities = () =>
|
||||||
alovaInstance.Get<EntityItem[]>('/rest/customentities', {
|
alovaInstance.Get<EntityItem[]>('/rest/entities', {
|
||||||
name: 'entities',
|
name: 'entities',
|
||||||
transformData(data: any) {
|
transformData(data: any) {
|
||||||
return data.entities.map((ei: EntityItem) => ({
|
return data.entities.map((ei: EntityItem) => ({
|
||||||
@@ -106,4 +104,4 @@ export const readCustomEntities = () =>
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customentities', data);
|
export const writeEntities = (data: any) => alovaInstance.Post('/rest/entities', data);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export interface Settings {
|
|||||||
syslog_mark_interval: number;
|
syslog_mark_interval: number;
|
||||||
syslog_host: string;
|
syslog_host: string;
|
||||||
syslog_port: number;
|
syslog_port: number;
|
||||||
boiler_heatingoff: boolean;
|
|
||||||
shower_timer: boolean;
|
shower_timer: boolean;
|
||||||
shower_alert: boolean;
|
shower_alert: boolean;
|
||||||
shower_alert_coldshot: number;
|
shower_alert_coldshot: number;
|
||||||
@@ -69,7 +68,6 @@ export interface Device {
|
|||||||
d: number; // deviceid
|
d: number; // deviceid
|
||||||
p: number; // productid
|
p: number; // productid
|
||||||
v: string; // version
|
v: string; // version
|
||||||
e: number; // entities
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TemperatureSensor {
|
export interface TemperatureSensor {
|
||||||
@@ -102,7 +100,6 @@ export interface SensorData {
|
|||||||
ts: TemperatureSensor[];
|
ts: TemperatureSensor[];
|
||||||
as: AnalogSensor[];
|
as: AnalogSensor[];
|
||||||
analog_enabled: boolean;
|
analog_enabled: boolean;
|
||||||
platform: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreData {
|
export interface CoreData {
|
||||||
@@ -130,7 +127,7 @@ export interface DeviceValue {
|
|||||||
c?: string; // command, optional
|
c?: string; // command, optional
|
||||||
l?: string[]; // list, optional
|
l?: string[]; // list, optional
|
||||||
h?: string; // help text, optional
|
h?: string; // help text, optional
|
||||||
s?: string; // steps for up/down, optional
|
s?: number; // steps for up/down, optional
|
||||||
m?: number; // min, optional
|
m?: number; // min, optional
|
||||||
x?: number; // max, optional
|
x?: number; // max, optional
|
||||||
}
|
}
|
||||||
@@ -176,8 +173,7 @@ export enum DeviceValueUOM {
|
|||||||
M3,
|
M3,
|
||||||
L,
|
L,
|
||||||
KMIN,
|
KMIN,
|
||||||
K,
|
K
|
||||||
VOLTS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeviceValueUOM_s = [
|
export const DeviceValueUOM_s = [
|
||||||
@@ -203,8 +199,7 @@ export const DeviceValueUOM_s = [
|
|||||||
'm³',
|
'm³',
|
||||||
'l',
|
'l',
|
||||||
'K*min',
|
'K*min',
|
||||||
'K',
|
'K'
|
||||||
'V'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export enum AnalogType {
|
export enum AnalogType {
|
||||||
@@ -240,9 +235,7 @@ type BoardProfiles = {
|
|||||||
|
|
||||||
export const BOARD_PROFILES: BoardProfiles = {
|
export const BOARD_PROFILES: BoardProfiles = {
|
||||||
S32: 'BBQKees Gateway S32',
|
S32: 'BBQKees Gateway S32',
|
||||||
S32S3: 'BBQKees Gateway S3',
|
|
||||||
E32: 'BBQKees Gateway E32',
|
E32: 'BBQKees Gateway E32',
|
||||||
E32V2: 'BBQKees Gateway E32 V2',
|
|
||||||
NODEMCU: 'NodeMCU 32S',
|
NODEMCU: 'NodeMCU 32S',
|
||||||
'MH-ET': 'MH-ET Live D1 Mini',
|
'MH-ET': 'MH-ET Live D1 Mini',
|
||||||
LOLIN: 'Lolin D32',
|
LOLIN: 'Lolin D32',
|
||||||
@@ -250,7 +243,8 @@ export const BOARD_PROFILES: BoardProfiles = {
|
|||||||
OLIMEXPOE: 'Olimex ESP32-POE',
|
OLIMEXPOE: 'Olimex ESP32-POE',
|
||||||
C3MINI: 'Wemos C3 Mini',
|
C3MINI: 'Wemos C3 Mini',
|
||||||
S2MINI: 'Wemos S2 Mini',
|
S2MINI: 'Wemos S2 Mini',
|
||||||
S3MINI: 'Liligo S3'
|
S3MINI: 'Liligo S3',
|
||||||
|
S32S3: 'BBQKees Gateway S3'
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface BoardProfile {
|
export interface BoardProfile {
|
||||||
@@ -266,7 +260,8 @@ export interface BoardProfile {
|
|||||||
eth_clock_mode: number;
|
eth_clock_mode: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIdata {
|
export interface APIcall {
|
||||||
|
device: string;
|
||||||
entity: string;
|
entity: string;
|
||||||
id: any;
|
id: any;
|
||||||
}
|
}
|
||||||
@@ -364,7 +359,7 @@ export const enum DeviceType {
|
|||||||
CONTROLLER,
|
CONTROLLER,
|
||||||
CONNECT,
|
CONNECT,
|
||||||
ALERT,
|
ALERT,
|
||||||
EXTENSION,
|
PUMP,
|
||||||
GENERIC,
|
GENERIC,
|
||||||
HEATSOURCE,
|
HEATSOURCE,
|
||||||
CUSTOM,
|
CUSTOM,
|
||||||
@@ -384,16 +379,3 @@ export const enum DeviceValueType {
|
|||||||
STRING,
|
STRING,
|
||||||
CMD
|
CMD
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeviceValueTypeNames = [
|
|
||||||
'BOOL',
|
|
||||||
'INT',
|
|
||||||
'UINT',
|
|
||||||
'SHORT',
|
|
||||||
'USHORT',
|
|
||||||
'ULONG',
|
|
||||||
'TIME',
|
|
||||||
'ENUM',
|
|
||||||
'STRING',
|
|
||||||
'CMD'
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ export const GPIO_VALIDATOR = {
|
|||||||
if (
|
if (
|
||||||
value &&
|
value &&
|
||||||
(value === 1 ||
|
(value === 1 ||
|
||||||
(value >= 6 && value <= 11) ||
|
(value >= 6 && value <= 12) ||
|
||||||
|
(value >= 14 && value <= 15) ||
|
||||||
value === 20 ||
|
value === 20 ||
|
||||||
value === 24 ||
|
value === 24 ||
|
||||||
(value >= 28 && value <= 31) ||
|
(value >= 28 && value <= 31) ||
|
||||||
@@ -188,12 +189,12 @@ export const isGPIOUniqueValidator = (sensors: AnalogSensor[]) => ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const analogSensorItemValidation = (sensors: AnalogSensor[], creating: boolean, platform: string) =>
|
export const analogSensorItemValidation = (sensors: AnalogSensor[], creating: boolean) =>
|
||||||
new Schema({
|
new Schema({
|
||||||
n: [{ required: true, message: 'Name is required' }],
|
n: [{ required: true, message: 'Name is required' }],
|
||||||
g: [
|
g: [
|
||||||
{ required: true, message: 'GPIO is required' },
|
{ required: true, message: 'GPIO is required' },
|
||||||
platform === 'ESP32-S3' ? GPIO_VALIDATORS3 : platform === 'ESP32-C3' ? GPIO_VALIDATORC3 : GPIO_VALIDATOR,
|
GPIO_VALIDATOR,
|
||||||
...(creating ? [isGPIOUniqueValidator(sensors)] : [])
|
...(creating ? [isGPIOUniqueValidator(sensors)] : [])
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export interface MqttSettings {
|
|||||||
port: number;
|
port: number;
|
||||||
base: string;
|
base: string;
|
||||||
rootCA?: string;
|
rootCA?: string;
|
||||||
enableTLS?: boolean;
|
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
client_id: string;
|
client_id: string;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export interface NetworkStatus {
|
|||||||
|
|
||||||
export interface NetworkSettings {
|
export interface NetworkSettings {
|
||||||
ssid: string;
|
ssid: string;
|
||||||
bssid: string;
|
|
||||||
password: string;
|
password: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
static_ip_config: boolean;
|
static_ip_config: boolean;
|
||||||
|
|||||||
@@ -2,14 +2,9 @@ export interface SystemStatus {
|
|||||||
emsesp_version: string;
|
emsesp_version: string;
|
||||||
esp_platform: string;
|
esp_platform: string;
|
||||||
max_alloc_heap: number;
|
max_alloc_heap: number;
|
||||||
cpu_type: string;
|
|
||||||
cpu_rev: number;
|
|
||||||
cpu_cores: number;
|
|
||||||
cpu_freq_mhz: number;
|
cpu_freq_mhz: number;
|
||||||
free_heap: number;
|
free_heap: number;
|
||||||
arduino_version: string;
|
|
||||||
sdk_version: string;
|
sdk_version: string;
|
||||||
partition: string;
|
|
||||||
flash_chip_size: number;
|
flash_chip_size: number;
|
||||||
flash_chip_speed: number;
|
flash_chip_speed: number;
|
||||||
app_used: number;
|
app_used: number;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRequest, type Method } from 'alova';
|
import { useRequest, type Method } from 'alova';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
@@ -33,7 +33,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions2<D>) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onWriteSuccess(() => {
|
onWriteSuccess(() => {
|
||||||
toast.success(LL.UPDATED_OF(LL.SETTINGS(0)));
|
toast.success(LL.UPDATED_OF(LL.SETTINGS()));
|
||||||
setDirtyFlags([]);
|
setDirtyFlags([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/*
|
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import Sockette from 'sockette';
|
import Sockette from 'sockette';
|
||||||
@@ -90,4 +89,3 @@ export const useWs = <D>(wsUrl: string, wsThrottle = 100) => {
|
|||||||
|
|
||||||
return { connected, data, updateData } as const;
|
return { connected, data, updateData } as const;
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import type { NetworkSettings } from 'types';
|
|||||||
export const createNetworkSettingsValidator = (networkSettings: NetworkSettings) =>
|
export const createNetworkSettingsValidator = (networkSettings: NetworkSettings) =>
|
||||||
new Schema({
|
new Schema({
|
||||||
ssid: [{ type: 'string', max: 32, message: 'SSID must be 32 characters or less' }],
|
ssid: [{ type: 'string', max: 32, message: 'SSID must be 32 characters or less' }],
|
||||||
bssid: [{ type: 'string', max: 17, message: 'BSSID must be 17 characters or empty' }],
|
|
||||||
password: { type: 'string', max: 64, message: 'Password must be 64 characters or less' },
|
password: { type: 'string', max: 64, message: 'Password must be 64 characters or less' },
|
||||||
hostname: [{ required: true, message: 'Hostname is required' }, HOSTNAME_VALIDATOR],
|
hostname: [{ required: true, message: 'Hostname is required' }, HOSTNAME_VALIDATOR],
|
||||||
...(networkSettings.static_ip_config && {
|
...(networkSettings.static_ip_config && {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
"types": ["node"],
|
"types": ["vite/client", "vite-plugin-svgr/client", "node"],
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": false,
|
"esModuleInterop": false,
|
||||||
@@ -26,6 +26,6 @@
|
|||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "vite.config.ts"],
|
"include": ["src/**/*", "vite.config.ts", "progmem-generator.js"],
|
||||||
"exclude": ["node_modules", "dist", "src/**/*.test.tsx", "src/**/*.test.ts"]
|
"exclude": ["node_modules", "dist", "src/**/*.test.tsx", "src/**/*.test.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,58 @@
|
|||||||
import { defineConfig, splitVendorChunkPlugin } from 'vite';
|
import { defineConfig, type PluginOption } from 'vite';
|
||||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||||
import preact from '@preact/preset-vite';
|
import svgrPlugin from 'vite-plugin-svgr';
|
||||||
import viteImagemin from 'vite-plugin-imagemin';
|
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
|
import ProgmemGenerator from './progmem-generator';
|
||||||
|
import preact from '@preact/preset-vite';
|
||||||
|
|
||||||
export default defineConfig(({ command, mode }) => {
|
export default defineConfig(({ command, mode }) => {
|
||||||
if (command === 'serve') {
|
if (mode === 'hosted') {
|
||||||
console.log('Preparing for standalone build with server, mode=' + mode);
|
|
||||||
return {
|
return {
|
||||||
plugins: [preact(), viteTsconfigPaths()],
|
// hosted, ignore all errors, output to dist
|
||||||
|
plugins: [preact(), viteTsconfigPaths(), svgrPlugin(), visualizer({ gzipSize: true }) as PluginOption]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// normal build
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
preact(),
|
||||||
|
viteTsconfigPaths(),
|
||||||
|
svgrPlugin(),
|
||||||
|
ProgmemGenerator({ outputPath: '../lib/framework/WWWData.h', bytesPerLine: 20 })
|
||||||
|
],
|
||||||
|
|
||||||
|
build: {
|
||||||
|
outDir: 'build',
|
||||||
|
chunkSizeWarningLimit: 1024,
|
||||||
|
sourcemap: false,
|
||||||
|
manifest: false,
|
||||||
|
minify: mode === 'development' ? false : 'terser',
|
||||||
|
rollupOptions: {
|
||||||
|
/**
|
||||||
|
* Ignore "use client" waning since we are not using SSR
|
||||||
|
*/
|
||||||
|
onwarn(warning, warn) {
|
||||||
|
if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes(`"use client"`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
warn(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onwarn(warning, warn) {
|
||||||
|
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
warn(warning);
|
||||||
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
open: true,
|
open: true,
|
||||||
port: mode == 'production' ? 4173 : 3000,
|
port: 3000,
|
||||||
|
watch: {
|
||||||
|
usePolling: true
|
||||||
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/rest': 'http://localhost:3080',
|
'/rest': 'http://localhost:3080',
|
||||||
'/api': {
|
'/api': {
|
||||||
@@ -28,107 +69,4 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command === 'build' && mode === 'hosted') {
|
|
||||||
return {
|
|
||||||
plugins: [preact(), viteTsconfigPaths()],
|
|
||||||
build: {
|
|
||||||
chunkSizeWarningLimit: 1024
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// production build, both for hosted and building the firmware
|
|
||||||
if (command === 'build') {
|
|
||||||
return {
|
|
||||||
plugins: [
|
|
||||||
preact(),
|
|
||||||
viteTsconfigPaths(),
|
|
||||||
splitVendorChunkPlugin(),
|
|
||||||
{
|
|
||||||
...viteImagemin({
|
|
||||||
verbose: false,
|
|
||||||
gifsicle: {
|
|
||||||
optimizationLevel: 7,
|
|
||||||
interlaced: false
|
|
||||||
},
|
|
||||||
optipng: {
|
|
||||||
optimizationLevel: 7
|
|
||||||
},
|
|
||||||
mozjpeg: {
|
|
||||||
quality: 20
|
|
||||||
},
|
|
||||||
pngquant: {
|
|
||||||
quality: [0.8, 0.9],
|
|
||||||
speed: 4
|
|
||||||
},
|
|
||||||
svgo: {
|
|
||||||
plugins: [
|
|
||||||
{
|
|
||||||
name: 'removeViewBox'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'removeEmptyAttrs',
|
|
||||||
active: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
enforce: 'pre'
|
|
||||||
},
|
|
||||||
visualizer({
|
|
||||||
template: 'treemap', // or sunburst
|
|
||||||
open: false,
|
|
||||||
gzipSize: true,
|
|
||||||
brotliSize: true,
|
|
||||||
filename: 'analyse.html' // will be saved in project's root
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
build: {
|
|
||||||
// target: 'es2022',
|
|
||||||
chunkSizeWarningLimit: 1024,
|
|
||||||
minify: 'terser',
|
|
||||||
terserOptions: {
|
|
||||||
compress: {
|
|
||||||
passes: 4,
|
|
||||||
arrows: true,
|
|
||||||
drop_console: true,
|
|
||||||
drop_debugger: true,
|
|
||||||
sequences: true
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
// toplevel: true
|
|
||||||
// module: true
|
|
||||||
// properties: {
|
|
||||||
// regex: /^_/
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
ecma: 5,
|
|
||||||
enclose: false,
|
|
||||||
keep_classnames: false,
|
|
||||||
keep_fnames: false,
|
|
||||||
ie8: false,
|
|
||||||
module: false,
|
|
||||||
nameCache: null,
|
|
||||||
safari10: false,
|
|
||||||
toplevel: false
|
|
||||||
},
|
|
||||||
|
|
||||||
rollupOptions: {
|
|
||||||
output: {
|
|
||||||
manualChunks(id: string) {
|
|
||||||
if (id.includes('node_modules')) {
|
|
||||||
// creating a chunk to react routes deps. Reducing the vendor chunk size
|
|
||||||
if (id.includes('react-router-dom') || id.includes('@remix-run') || id.includes('react-router')) {
|
|
||||||
return '@react-router';
|
|
||||||
}
|
|
||||||
return 'vendor';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
7739
interface/yarn.lock
7739
interface/yarn.lock
File diff suppressed because it is too large
Load Diff
3440
lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp
Normal file
3440
lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
410
lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h
Normal file
410
lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h
Normal file
@@ -0,0 +1,410 @@
|
|||||||
|
/*!
|
||||||
|
* @file Adafruit_NeoPixel.h
|
||||||
|
*
|
||||||
|
* This is part of Adafruit's NeoPixel library for the Arduino platform,
|
||||||
|
* allowing a broad range of microcontroller boards (most AVR boards,
|
||||||
|
* many ARM devices, ESP8266 and ESP32, among others) to control Adafruit
|
||||||
|
* NeoPixels, FLORA RGB Smart Pixels and compatible devices -- WS2811,
|
||||||
|
* WS2812, WS2812B, SK6812, etc.
|
||||||
|
*
|
||||||
|
* Adafruit invests time and resources providing this open source code,
|
||||||
|
* please support Adafruit and open-source hardware by purchasing products
|
||||||
|
* from Adafruit!
|
||||||
|
*
|
||||||
|
* Written by Phil "Paint Your Dragon" Burgess for Adafruit Industries,
|
||||||
|
* with contributions by PJRC, Michael Miller and other members of the
|
||||||
|
* open source community.
|
||||||
|
*
|
||||||
|
* This file is part of the Adafruit_NeoPixel library.
|
||||||
|
*
|
||||||
|
* Adafruit_NeoPixel is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Adafruit_NeoPixel is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with NeoPixel. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ADAFRUIT_NEOPIXEL_H
|
||||||
|
#define ADAFRUIT_NEOPIXEL_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
#if (ARDUINO >= 100)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#else
|
||||||
|
#include <WProgram.h>
|
||||||
|
#include <pins_arduino.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_TINYUSB // For Serial when selecting TinyUSB
|
||||||
|
#include <Adafruit_TinyUSB.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TARGET_LPC1768
|
||||||
|
#include <Arduino.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_RP2040)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
#include "rp2040_pio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The order of primary colors in the NeoPixel data stream can vary among
|
||||||
|
// device types, manufacturers and even different revisions of the same
|
||||||
|
// item. The third parameter to the Adafruit_NeoPixel constructor encodes
|
||||||
|
// the per-pixel byte offsets of the red, green and blue primaries (plus
|
||||||
|
// white, if present) in the data stream -- the following #defines provide
|
||||||
|
// an easier-to-use named version for each permutation. e.g. NEO_GRB
|
||||||
|
// indicates a NeoPixel-compatible device expecting three bytes per pixel,
|
||||||
|
// with the first byte transmitted containing the green value, second
|
||||||
|
// containing red and third containing blue. The in-memory representation
|
||||||
|
// of a chain of NeoPixels is the same as the data-stream order; no
|
||||||
|
// re-ordering of bytes is required when issuing data to the chain.
|
||||||
|
// Most of these values won't exist in real-world devices, but it's done
|
||||||
|
// this way so we're ready for it (also, if using the WS2811 driver IC,
|
||||||
|
// one might have their pixels set up in any weird permutation).
|
||||||
|
|
||||||
|
// Bits 5,4 of this value are the offset (0-3) from the first byte of a
|
||||||
|
// pixel to the location of the red color byte. Bits 3,2 are the green
|
||||||
|
// offset and 1,0 are the blue offset. If it is an RGBW-type device
|
||||||
|
// (supporting a white primary in addition to R,G,B), bits 7,6 are the
|
||||||
|
// offset to the white byte...otherwise, bits 7,6 are set to the same value
|
||||||
|
// as 5,4 (red) to indicate an RGB (not RGBW) device.
|
||||||
|
// i.e. binary representation:
|
||||||
|
// 0bWWRRGGBB for RGBW devices
|
||||||
|
// 0bRRRRGGBB for RGB
|
||||||
|
|
||||||
|
// RGB NeoPixel permutations; white and red offsets are always same
|
||||||
|
// Offset: W R G B
|
||||||
|
#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2)) ///< Transmit as R,G,B
|
||||||
|
#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1)) ///< Transmit as R,B,G
|
||||||
|
#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2)) ///< Transmit as G,R,B
|
||||||
|
#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,R
|
||||||
|
#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0)) ///< Transmit as B,R,G
|
||||||
|
#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,R
|
||||||
|
|
||||||
|
// RGBW NeoPixel permutations; all 4 offsets are distinct
|
||||||
|
// Offset: W R G B
|
||||||
|
#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3)) ///< Transmit as W,R,G,B
|
||||||
|
#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2)) ///< Transmit as W,R,B,G
|
||||||
|
#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3)) ///< Transmit as W,G,R,B
|
||||||
|
#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2)) ///< Transmit as W,G,B,R
|
||||||
|
#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1)) ///< Transmit as W,B,R,G
|
||||||
|
#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1)) ///< Transmit as W,B,G,R
|
||||||
|
|
||||||
|
#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3)) ///< Transmit as R,W,G,B
|
||||||
|
#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2)) ///< Transmit as R,W,B,G
|
||||||
|
#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3)) ///< Transmit as R,G,W,B
|
||||||
|
#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2)) ///< Transmit as R,G,B,W
|
||||||
|
#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1)) ///< Transmit as R,B,W,G
|
||||||
|
#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1)) ///< Transmit as R,B,G,W
|
||||||
|
|
||||||
|
#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3)) ///< Transmit as G,W,R,B
|
||||||
|
#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2)) ///< Transmit as G,W,B,R
|
||||||
|
#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3)) ///< Transmit as G,R,W,B
|
||||||
|
#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2)) ///< Transmit as G,R,B,W
|
||||||
|
#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,W,R
|
||||||
|
#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,R,W
|
||||||
|
|
||||||
|
#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0)) ///< Transmit as B,W,R,G
|
||||||
|
#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0)) ///< Transmit as B,W,G,R
|
||||||
|
#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0)) ///< Transmit as B,R,W,G
|
||||||
|
#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0)) ///< Transmit as B,R,G,W
|
||||||
|
#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,W,R
|
||||||
|
#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,R,W
|
||||||
|
|
||||||
|
// Add NEO_KHZ400 to the color order value to indicate a 400 KHz device.
|
||||||
|
// All but the earliest v1 NeoPixels expect an 800 KHz data stream, this is
|
||||||
|
// the default if unspecified. Because flash space is very limited on ATtiny
|
||||||
|
// devices (e.g. Trinket, Gemma), v1 NeoPixels aren't handled by default on
|
||||||
|
// those chips, though it can be enabled by removing the ifndef/endif below,
|
||||||
|
// but code will be bigger. Conversely, can disable the NEO_KHZ400 line on
|
||||||
|
// other MCUs to remove v1 support and save a little space.
|
||||||
|
|
||||||
|
#define NEO_KHZ800 0x0000 ///< 800 KHz data transmission
|
||||||
|
#ifndef __AVR_ATtiny85__
|
||||||
|
#define NEO_KHZ400 0x0100 ///< 400 KHz data transmission
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If 400 KHz support is enabled, the third parameter to the constructor
|
||||||
|
// requires a 16-bit value (in order to select 400 vs 800 KHz speed).
|
||||||
|
// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value
|
||||||
|
// is sufficient to encode pixel color order, saving some space.
|
||||||
|
|
||||||
|
#ifdef NEO_KHZ400
|
||||||
|
typedef uint16_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor
|
||||||
|
#else
|
||||||
|
typedef uint8_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// These two tables are declared outside the Adafruit_NeoPixel class
|
||||||
|
// because some boards may require oldschool compilers that don't
|
||||||
|
// handle the C++11 constexpr keyword.
|
||||||
|
|
||||||
|
/* A PROGMEM (flash mem) table containing 8-bit unsigned sine wave (0-255).
|
||||||
|
Copy & paste this snippet into a Python REPL to regenerate:
|
||||||
|
import math
|
||||||
|
for x in range(256):
|
||||||
|
print("{:3},".format(int((math.sin(x/128.0*math.pi)+1.0)*127.5+0.5))),
|
||||||
|
if x&15 == 15: print
|
||||||
|
*/
|
||||||
|
static const uint8_t PROGMEM _NeoPixelSineTable[256] = {
|
||||||
|
128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170,
|
||||||
|
173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211,
|
||||||
|
213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240,
|
||||||
|
241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254,
|
||||||
|
254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251,
|
||||||
|
250, 250, 249, 248, 246, 245, 244, 243, 241, 240, 238, 237, 235, 234, 232,
|
||||||
|
230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198,
|
||||||
|
196, 193, 190, 188, 185, 182, 179, 176, 173, 170, 167, 165, 162, 158, 155,
|
||||||
|
152, 149, 146, 143, 140, 137, 134, 131, 128, 124, 121, 118, 115, 112, 109,
|
||||||
|
106, 103, 100, 97, 93, 90, 88, 85, 82, 79, 76, 73, 70, 67, 65,
|
||||||
|
62, 59, 57, 54, 52, 49, 47, 44, 42, 40, 37, 35, 33, 31, 29,
|
||||||
|
27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, 10, 9, 7, 6,
|
||||||
|
5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11,
|
||||||
|
12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37,
|
||||||
|
40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
|
||||||
|
79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121,
|
||||||
|
124};
|
||||||
|
|
||||||
|
/* Similar to above, but for an 8-bit gamma-correction table.
|
||||||
|
Copy & paste this snippet into a Python REPL to regenerate:
|
||||||
|
import math
|
||||||
|
gamma=2.6
|
||||||
|
for x in range(256):
|
||||||
|
print("{:3},".format(int(math.pow((x)/255.0,gamma)*255.0+0.5))),
|
||||||
|
if x&15 == 15: print
|
||||||
|
*/
|
||||||
|
static const uint8_t PROGMEM _NeoPixelGammaTable[256] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3,
|
||||||
|
3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
|
||||||
|
6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
|
||||||
|
11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17,
|
||||||
|
17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||||
|
25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35,
|
||||||
|
36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 48,
|
||||||
|
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||||
|
64, 65, 66, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 80, 81,
|
||||||
|
82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 97, 99, 100, 102,
|
||||||
|
103, 105, 106, 108, 109, 111, 112, 114, 115, 117, 119, 120, 122, 124, 125,
|
||||||
|
127, 129, 130, 132, 134, 136, 137, 139, 141, 143, 145, 146, 148, 150, 152,
|
||||||
|
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182,
|
||||||
|
184, 186, 188, 191, 193, 195, 197, 199, 202, 204, 206, 209, 211, 213, 215,
|
||||||
|
218, 220, 223, 225, 227, 230, 232, 235, 237, 240, 242, 245, 247, 250, 252,
|
||||||
|
255};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief Class that stores state and functions for interacting with
|
||||||
|
Adafruit NeoPixels and compatible devices.
|
||||||
|
*/
|
||||||
|
class Adafruit_NeoPixel {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor: number of LEDs, pin number, LED type
|
||||||
|
Adafruit_NeoPixel(uint16_t n, int16_t pin = 6,
|
||||||
|
neoPixelType type = NEO_GRB + NEO_KHZ800);
|
||||||
|
Adafruit_NeoPixel(void);
|
||||||
|
~Adafruit_NeoPixel();
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void show(void);
|
||||||
|
void setPin(int16_t p);
|
||||||
|
void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
|
||||||
|
void setPixelColor(uint16_t n, uint32_t c);
|
||||||
|
void fill(uint32_t c = 0, uint16_t first = 0, uint16_t count = 0);
|
||||||
|
void setBrightness(uint8_t);
|
||||||
|
void clear(void);
|
||||||
|
void updateLength(uint16_t n);
|
||||||
|
void updateType(neoPixelType t);
|
||||||
|
/*!
|
||||||
|
@brief Check whether a call to show() will start sending data
|
||||||
|
immediately or will 'block' for a required interval. NeoPixels
|
||||||
|
require a short quiet time (about 300 microseconds) after the
|
||||||
|
last bit is received before the data 'latches' and new data can
|
||||||
|
start being received. Usually one's sketch is implicitly using
|
||||||
|
this time to generate a new frame of animation...but if it
|
||||||
|
finishes very quickly, this function could be used to see if
|
||||||
|
there's some idle time available for some low-priority
|
||||||
|
concurrent task.
|
||||||
|
@return 1 or true if show() will start sending immediately, 0 or false
|
||||||
|
if show() would block (meaning some idle time is available).
|
||||||
|
*/
|
||||||
|
bool canShow(void) {
|
||||||
|
// It's normal and possible for endTime to exceed micros() if the
|
||||||
|
// 32-bit clock counter has rolled over (about every 70 minutes).
|
||||||
|
// Since both are uint32_t, a negative delta correctly maps back to
|
||||||
|
// positive space, and it would seem like the subtraction below would
|
||||||
|
// suffice. But a problem arises if code invokes show() very
|
||||||
|
// infrequently...the micros() counter may roll over MULTIPLE times in
|
||||||
|
// that interval, the delta calculation is no longer correct and the
|
||||||
|
// next update may stall for a very long time. The check below resets
|
||||||
|
// the latch counter if a rollover has occurred. This can cause an
|
||||||
|
// extra delay of up to 300 microseconds in the rare case where a
|
||||||
|
// show() call happens precisely around the rollover, but that's
|
||||||
|
// neither likely nor especially harmful, vs. other code that might
|
||||||
|
// stall for 30+ minutes, or having to document and frequently remind
|
||||||
|
// and/or provide tech support explaining an unintuitive need for
|
||||||
|
// show() calls at least once an hour.
|
||||||
|
uint32_t now = micros();
|
||||||
|
if (endTime > now) {
|
||||||
|
endTime = now;
|
||||||
|
}
|
||||||
|
return (now - endTime) >= 300L;
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
@brief Get a pointer directly to the NeoPixel data buffer in RAM.
|
||||||
|
Pixel data is stored in a device-native format (a la the NEO_*
|
||||||
|
constants) and is not translated here. Applications that access
|
||||||
|
this buffer will need to be aware of the specific data format
|
||||||
|
and handle colors appropriately.
|
||||||
|
@return Pointer to NeoPixel buffer (uint8_t* array).
|
||||||
|
@note This is for high-performance applications where calling
|
||||||
|
setPixelColor() on every single pixel would be too slow (e.g.
|
||||||
|
POV or light-painting projects). There is no bounds checking
|
||||||
|
on the array, creating tremendous potential for mayhem if one
|
||||||
|
writes past the ends of the buffer. Great power, great
|
||||||
|
responsibility and all that.
|
||||||
|
*/
|
||||||
|
uint8_t *getPixels(void) const { return pixels; };
|
||||||
|
uint8_t getBrightness(void) const;
|
||||||
|
/*!
|
||||||
|
@brief Retrieve the pin number used for NeoPixel data output.
|
||||||
|
@return Arduino pin number (-1 if not set).
|
||||||
|
*/
|
||||||
|
int16_t getPin(void) const { return pin; };
|
||||||
|
/*!
|
||||||
|
@brief Return the number of pixels in an Adafruit_NeoPixel strip object.
|
||||||
|
@return Pixel count (0 if not set).
|
||||||
|
*/
|
||||||
|
uint16_t numPixels(void) const { return numLEDs; }
|
||||||
|
uint32_t getPixelColor(uint16_t n) const;
|
||||||
|
/*!
|
||||||
|
@brief An 8-bit integer sine wave function, not directly compatible
|
||||||
|
with standard trigonometric units like radians or degrees.
|
||||||
|
@param x Input angle, 0-255; 256 would loop back to zero, completing
|
||||||
|
the circle (equivalent to 360 degrees or 2 pi radians).
|
||||||
|
One can therefore use an unsigned 8-bit variable and simply
|
||||||
|
add or subtract, allowing it to overflow/underflow and it
|
||||||
|
still does the expected contiguous thing.
|
||||||
|
@return Sine result, 0 to 255, or -128 to +127 if type-converted to
|
||||||
|
a signed int8_t, but you'll most likely want unsigned as this
|
||||||
|
output is often used for pixel brightness in animation effects.
|
||||||
|
*/
|
||||||
|
static uint8_t sine8(uint8_t x) {
|
||||||
|
return pgm_read_byte(&_NeoPixelSineTable[x]); // 0-255 in, 0-255 out
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
@brief An 8-bit gamma-correction function for basic pixel brightness
|
||||||
|
adjustment. Makes color transitions appear more perceptially
|
||||||
|
correct.
|
||||||
|
@param x Input brightness, 0 (minimum or off/black) to 255 (maximum).
|
||||||
|
@return Gamma-adjusted brightness, can then be passed to one of the
|
||||||
|
setPixelColor() functions. This uses a fixed gamma correction
|
||||||
|
exponent of 2.6, which seems reasonably okay for average
|
||||||
|
NeoPixels in average tasks. If you need finer control you'll
|
||||||
|
need to provide your own gamma-correction function instead.
|
||||||
|
*/
|
||||||
|
static uint8_t gamma8(uint8_t x) {
|
||||||
|
return pgm_read_byte(&_NeoPixelGammaTable[x]); // 0-255 in, 0-255 out
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
@brief Convert separate red, green and blue values into a single
|
||||||
|
"packed" 32-bit RGB color.
|
||||||
|
@param r Red brightness, 0 to 255.
|
||||||
|
@param g Green brightness, 0 to 255.
|
||||||
|
@param b Blue brightness, 0 to 255.
|
||||||
|
@return 32-bit packed RGB value, which can then be assigned to a
|
||||||
|
variable for later use or passed to the setPixelColor()
|
||||||
|
function. Packed RGB format is predictable, regardless of
|
||||||
|
LED strand color order.
|
||||||
|
*/
|
||||||
|
static uint32_t Color(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
@brief Convert separate red, green, blue and white values into a
|
||||||
|
single "packed" 32-bit WRGB color.
|
||||||
|
@param r Red brightness, 0 to 255.
|
||||||
|
@param g Green brightness, 0 to 255.
|
||||||
|
@param b Blue brightness, 0 to 255.
|
||||||
|
@param w White brightness, 0 to 255.
|
||||||
|
@return 32-bit packed WRGB value, which can then be assigned to a
|
||||||
|
variable for later use or passed to the setPixelColor()
|
||||||
|
function. Packed WRGB format is predictable, regardless of
|
||||||
|
LED strand color order.
|
||||||
|
*/
|
||||||
|
static uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||||
|
return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||||
|
}
|
||||||
|
static uint32_t ColorHSV(uint16_t hue, uint8_t sat = 255, uint8_t val = 255);
|
||||||
|
/*!
|
||||||
|
@brief A gamma-correction function for 32-bit packed RGB or WRGB
|
||||||
|
colors. Makes color transitions appear more perceptially
|
||||||
|
correct.
|
||||||
|
@param x 32-bit packed RGB or WRGB color.
|
||||||
|
@return Gamma-adjusted packed color, can then be passed in one of the
|
||||||
|
setPixelColor() functions. Like gamma8(), this uses a fixed
|
||||||
|
gamma correction exponent of 2.6, which seems reasonably okay
|
||||||
|
for average NeoPixels in average tasks. If you need finer
|
||||||
|
control you'll need to provide your own gamma-correction
|
||||||
|
function instead.
|
||||||
|
*/
|
||||||
|
static uint32_t gamma32(uint32_t x);
|
||||||
|
|
||||||
|
void rainbow(uint16_t first_hue = 0, int8_t reps = 1,
|
||||||
|
uint8_t saturation = 255, uint8_t brightness = 255,
|
||||||
|
bool gammify = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(ARDUINO_ARCH_RP2040)
|
||||||
|
void rp2040Init(uint8_t pin, bool is800KHz);
|
||||||
|
void rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled...
|
||||||
|
bool is800KHz; ///< true if 800 KHz pixels
|
||||||
|
#endif
|
||||||
|
bool begun; ///< true if begin() previously called
|
||||||
|
uint16_t numLEDs; ///< Number of RGB LEDs in strip
|
||||||
|
uint16_t numBytes; ///< Size of 'pixels' buffer below
|
||||||
|
int16_t pin; ///< Output pin number (-1 if not yet set)
|
||||||
|
uint8_t brightness; ///< Strip brightness 0-255 (stored as +1)
|
||||||
|
uint8_t *pixels; ///< Holds LED color values (3 or 4 bytes each)
|
||||||
|
uint8_t rOffset; ///< Red index within each 3- or 4-byte pixel
|
||||||
|
uint8_t gOffset; ///< Index of green byte
|
||||||
|
uint8_t bOffset; ///< Index of blue byte
|
||||||
|
uint8_t wOffset; ///< Index of white (==rOffset if no white)
|
||||||
|
uint32_t endTime; ///< Latch timing reference
|
||||||
|
#ifdef __AVR__
|
||||||
|
volatile uint8_t *port; ///< Output PORT register
|
||||||
|
uint8_t pinMask; ///< Output PORT bitmask
|
||||||
|
#endif
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32)
|
||||||
|
GPIO_TypeDef *gpioPort; ///< Output GPIO PORT
|
||||||
|
uint32_t gpioPin; ///< Output GPIO PIN
|
||||||
|
#endif
|
||||||
|
#if defined(ARDUINO_ARCH_RP2040)
|
||||||
|
PIO pio = pio0;
|
||||||
|
int sm = 0;
|
||||||
|
bool init = true;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADAFRUIT_NEOPIXEL_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user