Merge remote-tracking branch 'origin/dev' for 3.6.5

This commit is contained in:
proddy
2024-03-23 17:56:05 +01:00
444 changed files with 21644 additions and 19030 deletions

View File

@@ -48,6 +48,10 @@ jobs:
run: | run: |
platformio run -e ci_s3 platformio run -e ci_s3
- name: Build E32V2 firmware
run: |
platformio run -e ci_16M
- name: Create a GH Release - name: Create a GH Release
id: 'automatic_releases' id: 'automatic_releases'
uses: 'marvinpinto/action-automatic-releases@latest' uses: 'marvinpinto/action-automatic-releases@latest'

15
.gitignore vendored
View File

@@ -1,8 +1,5 @@
# vscode # vscode
.vscode/c_cpp_properties.json .vscode/*
.vscode/extensions.json
.vscode/launch.json
# .vscode/settings.json
# c++ compiling # c++ compiling
.clang_complete .clang_complete
@@ -12,11 +9,11 @@ cppcheck.out.xml
# platformio # platformio
.pio .pio
pio_local.ini pio_local.ini
*_old
# OS specific # OS specific
.DS_Store .DS_Store
*Thumbs.db *Thumbs.db
emsesp
# web specfic # web specfic
build/ build/
@@ -38,12 +35,13 @@ stats.html
!.yarn/versions !.yarn/versions
yarn.lock yarn.lock
interface/analyse.html interface/analyse.html
interface/vite.config.ts.timestamp*
# scripts # scripts
test.sh test.sh
scripts/run.sh scripts/run.sh
scripts/__pycache__ scripts/__pycache__
/scripts/stackdmp.txt scripts/stackdmp.txt
# i18n generated files # i18n generated files
interface/src/i18n/i18n-react.tsx interface/src/i18n/i18n-react.tsx
@@ -57,7 +55,6 @@ interface/src/i18n/i18n-util.async.ts
sonar/ sonar/
bw-output/ bw-output/
# entity dump results # testing
# dump_entities.csv emsesp
# dump_entities.xls*

View File

@@ -2,8 +2,6 @@
// 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": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"platformio.platformio-ide" "platformio.platformio-ide"
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [

89
.vscode/settings.json vendored
View File

@@ -1,89 +0,0 @@
{
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
},
"editor.codeActionsOnSave": {
"source.fixAll": true
// "source.organizeImports": true
},
"eslint.nodePath": "interface/.yarn/sdks",
"eslint.workingDirectories": ["interface"],
"prettier.prettierPath": "",
"typescript.enablePromptUseWorkspaceTsdk": true,
"files.associations": {
"*.tsx": "typescriptreact",
"*.tcc": "cpp",
"optional": "cpp",
"istream": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"array": "cpp",
"functional": "cpp",
"regex": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"string": "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": [
"**/vendor/**",
"**/node_modules/**",
"**/dist/**",
"**/bower_components/**",
"**/build/**",
"**/.vscode/**",
"**/.github/**",
"**/_output/**",
"**/*.min.*",
"**/*.map",
"**/ArduinoJson/**"
],
"cSpell.enableFiletypes": ["!cpp"]
}

18
.vscode/tasks.json vendored
View File

@@ -1,18 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "build standalone emsesp",
"command": "make",
"args": [],
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@@ -5,6 +5,56 @@ 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.5] March 23 2024
## **IMPORTANT! BREAKING CHANGES**
- The Wifi Tx Power setting in Network Settings will be reset to Auto
## 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 (Slovak) language. Thanks @misa1515
- CPU info [#1497](https://github.com/emsesp/EMS-ESP32/pull/1497)
- Show network hostname in Web UI under Network Status
- Improved HA Discovery so each section (EMS device, Scheduler, Analog, Temperature, Custom, Shower) have their own section
- boiler Bosch C1200W, id 12, [#1536](https://github.com/emsesp/EMS-ESP32/issues/1536)
- mixer MM100 telegram 0x2CC [#1554](https://github.com/emsesp/EMS-ESP32/issues/1554)
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
- custom variables [#1423](https://github.com/emsesp/EMS-ESP32/issues/1423)
- weather compensation [#1642](https://github.com/emsesp/EMS-ESP32/issues/1642)
- env and partitions for DevKitC-1-N32R8 [#1635](https://github.com/emsesp/EMS-ESP32/discussions/1635)
- command `restart partitionname` and button long press to start with other partition [#1657](https://github.com/emsesp/EMS-ESP32/issues/1657)
- command `set service <mqtt|ota|ntp|ap> <enable|disable>` [#1663](https://github.com/emsesp/EMS-ESP32/issues/1663)
## 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 HA name and grouping to be consistent [#1528](https://github.com/emsesp/EMS-ESP32/issues/1528)
- MQTT autodiscovery in Domoticz not working [#1360](https://github.com/emsesp/EMS-ESP32/issues/1528)
- dhw comfort for new ems+, [#1495](https://github.com/emsesp/EMS-ESP32/issues/1495)
- added writeable icon to Web's Custom Entity page for each entity shown in the table
- Wifi Tx Power not adjusted [#1614](https://github.com/emsesp/EMS-ESP32/issues/1614)
- MQTT discovery of custom entity doesn't consider type of data [#1587](https://github.com/emsesp/EMS-ESP32/issues/1587)
- WiFi TxPower wasn't correctly used. Added an 'Auto' setting, which is the default.
- dns w/wo IPv6 [#1644](https://github.com/emsesp/EMS-ESP32/issues/1644)
## Changed
- HA don't set entity_category to Diagnostic/Configuration for EMS entities [#1459](https://github.com/emsesp/EMS-ESP32/discussions/1459)
- upgraded ArduinoJson to 7.0.0 #1538 and then 7.0.2
- small changes to the API for analog and temperature sensors
- Length of mqtt Broker adress [#1619](https://github.com/emsesp/EMS-ESP32/issues/1619)
- C++ optimizations - see <https://github.com/emsesp/EMS-ESP32/pull/1615>
- Send MQTT heartbeat immediately after connection [#1628](https://github.com/emsesp/EMS-ESP32/issues/1628)
- 16MB partitions with second nvs, larger FS, Coredump, optional factory partition
- stop fetching empty telegrams after 5 min
## [3.6.4] November 24 2023 ## [3.6.4] November 24 2023
## **IMPORTANT! BREAKING CHANGES** ## **IMPORTANT! BREAKING CHANGES**
@@ -236,7 +286,7 @@ There are breaking changes between 3.5.x and earlier versions of 3.6.0. Please r
- fix Table resizing in WebUI [#519](https://github.com/emsesp/EMS-ESP32/issues/519) - fix Table resizing in WebUI [#519](https://github.com/emsesp/EMS-ESP32/issues/519)
- allow larger customization files [#570](https://github.com/emsesp/EMS-ESP32/issues/570) - allow larger customization files [#570](https://github.com/emsesp/EMS-ESP32/issues/570)
- losing entitiy wwcomfort [#581](https://github.com/emsesp/EMS-ESP32/issues/581) - losing entity wwcomfort [#581](https://github.com/emsesp/EMS-ESP32/issues/581)
## Changed ## Changed

View File

@@ -1,6 +1,6 @@
# Changelog # Changelog
## [3.6.5] ## [3.x]
## **IMPORTANT! BREAKING CHANGES** ## **IMPORTANT! BREAKING CHANGES**

View File

@@ -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.5-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Sources & Files # Sources & Files

View File

@@ -1,6 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000, nvs, data, nvs, 0x9000, 0x005000,
otadata, data, ota, , 0x2000, otadata, data, ota, , 0x002000,
app0, app, ota_0, , 0x7F0000, app0, app, ota_0, , 0x5D0000,
app1, app, ota_1, , 0x7F0000, app1, app, ota_1, , 0x5D0000,
spiffs, data, spiffs, , 64K, nvs1, data, nvs, , 0x040000,
spiffs, data, spiffs, , 0x400000,
coredump, data, coredump,, 0x010000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000 0x005000
3 otadata data ota 0x2000 0x002000
4 app0 app ota_0 0x7F0000 0x5D0000
5 app1 app ota_1 0x7F0000 0x5D0000
6 spiffs nvs1 data spiffs nvs 64K 0x040000
7 spiffs data spiffs 0x400000
8 coredump data coredump 0x010000

View File

@@ -0,0 +1,9 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x005000,
otadata, data, ota, , 0x002000,
boot, app, factory, , 0x280000,
app0, app, ota_0, , 0x590000,
app1, app, ota_1, , 0x590000,
nvs1, data, nvs, , 0x040000,
spiffs, data, spiffs, , 0x200000,
coredump, data, coredump,, 0x010000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x005000
3 otadata data ota 0x002000
4 boot app factory 0x280000
5 app0 app ota_0 0x590000
6 app1 app ota_1 0x590000
7 nvs1 data nvs 0x040000
8 spiffs data spiffs 0x200000
9 coredump data coredump 0x010000

8
esp32_partition_32M.csv Normal file
View File

@@ -0,0 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x005000,
otadata, data, ota, , 0x002000,
app0, app, ota_0, , 0xDD0000,
app1, app, ota_1, , 0xDD0000,
nvs1, data, nvs, , 0x040000,
spiffs, data, spiffs, , 0x400000,
coredump, data, coredump,, 0x010000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x005000
3 otadata data ota 0x002000
4 app0 app ota_0 0xDD0000
5 app1 app ota_1 0xDD0000
6 nvs1 data nvs 0x040000
7 spiffs data spiffs 0x400000
8 coredump data coredump 0x010000

View File

@@ -36,7 +36,6 @@ build_flags =
-D FACTORY_MQTT_PORT=1883 -D FACTORY_MQTT_PORT=1883
-D FACTORY_MQTT_USERNAME=\"\" -D FACTORY_MQTT_USERNAME=\"\"
-D FACTORY_MQTT_PASSWORD=\"\" -D FACTORY_MQTT_PASSWORD=\"\"
-D FACTORY_MQTT_CLIENT_ID=\"ems-esp\"
-D FACTORY_MQTT_KEEP_ALIVE=60 -D FACTORY_MQTT_KEEP_ALIVE=60
-D FACTORY_MQTT_CLEAN_SESSION=false -D FACTORY_MQTT_CLEAN_SESSION=false
-D FACTORY_MQTT_MAX_TOPIC_LENGTH=128 -D FACTORY_MQTT_MAX_TOPIC_LENGTH=128

View File

@@ -5,8 +5,8 @@
}, },
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"airbnb/hooks", // "airbnb/hooks",
"airbnb-typescript", // "airbnb-typescript",
"plugin:react/recommended", "plugin:react/recommended",
"plugin:react/jsx-runtime", "plugin:react/jsx-runtime",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",

File diff suppressed because one or more lines are too long

View File

@@ -4,4 +4,4 @@ enableGlobalCache: false
nodeLinker: node-modules nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.2.cjs yarnPath: .yarn/releases/yarn-4.1.1.cjs

View File

@@ -12,28 +12,30 @@
"preview": "vite preview", "preview": "vite preview",
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted", "build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-api\" \"vite preview\"", "preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-api\" \"vite preview\"",
"mock-api": "node --watch ../mock-api ../mock-api/server.js", "mock-api": "bun --watch ../mock-api/server.ts",
"old_mock-api": "bun --watch ../mock-api/server.js",
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-api\" \"vite\"", "standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-api\" \"vite\"",
"old_standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:old_mock-api\" \"vite\"",
"typesafe-i18n": "typesafe-i18n --no-watch", "typesafe-i18n": "typesafe-i18n --no-watch",
"webUI": "node progmem-generator.js", "webUI": "node progmem-generator.js",
"format": "prettier --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.1", "@alova/adapter-xhr": "^1.0.3",
"@babel/core": "^7.23.3", "@babel/core": "^7.24.3",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.18", "@mui/icons-material": "^5.15.14",
"@mui/material": "^5.14.18", "@mui/material": "^5.15.14",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"@types/imagemin": "^8.0.5", "@types/imagemin": "^8.0.5",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.10.0", "@types/node": "^20.11.30",
"@types/react": "^18.2.38", "@types/react": "^18.2.69",
"@types/react-dom": "^18.2.17", "@types/react-dom": "^18.2.22",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"alova": "^2.14.0", "alova": "^2.18.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": "^4.0.0",
@@ -42,37 +44,35 @@
"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": "^5.0.1",
"react-router-dom": "^6.20.0", "react-router-dom": "^6.22.3",
"react-toastify": "^9.1.3", "react-toastify": "^10.0.5",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.3.2" "typescript": "^5.4.3"
}, },
"devDependencies": { "devDependencies": {
"@preact/compat": "^17.1.2", "@preact/compat": "^17.1.2",
"@preact/preset-vite": "^2.7.0", "@preact/preset-vite": "^2.8.2",
"@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/eslint-plugin": "^7.3.1",
"@typescript-eslint/parser": "^6.12.0", "@typescript-eslint/parser": "^7.3.1",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^8.54.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^9.1.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-autofix": "^1.1.0", "eslint-plugin-autofix": "^1.1.0",
"eslint-plugin-import": "^2.29.0", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "alpha", "eslint-plugin-prettier": "alpha",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"preact": "^10.19.2", "preact": "^10.20.1",
"prettier": "^3.1.0", "prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.9.3", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.24.0", "terser": "^5.29.2",
"vite": "^5.0.2", "vite": "^5.2.4",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^4.2.1" "vite-tsconfig-paths": "^4.3.2"
}, },
"packageManager": "yarn@4.0.2" "packageManager": "yarn@4.1.1"
} }

View File

@@ -2,6 +2,7 @@ import { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream }
import { resolve, relative, sep } from 'path'; import { resolve, relative, sep } from 'path';
import zlib from 'zlib'; import zlib from 'zlib';
import mime from 'mime-types'; import mime from 'mime-types';
import crypto from 'crypto';
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n'; const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
const INDENT = ' '; const INDENT = ' ';
@@ -11,13 +12,17 @@ const bytesPerLine = 20;
var totalSize = 0; var totalSize = 0;
const generateWWWClass = () => const generateWWWClass = () =>
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler; `typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
// Total size is ${totalSize} bytes
class WWWData { class WWWData {
${indent}public: ${indent}public:
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) { ${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
${fileInfo ${fileInfo
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`) .map(
(file) =>
`${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size}, "${file.hash}");`
)
.join('\n')} .join('\n')}
${indent.repeat(2)}} ${indent.repeat(2)}}
}; };
@@ -49,6 +54,12 @@ const writeFile = (relativeFilePath, buffer) => {
writeStream.write('const uint8_t ' + variable + '[] = {'); writeStream.write('const uint8_t ' + variable + '[] = {');
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 }); // const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
const zipBuffer = zlib.gzipSync(buffer, { level: 9 }); const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
// create sha
const hashSum = crypto.createHash('sha256');
hashSum.update(zipBuffer);
const hash = hashSum.digest('hex');
zipBuffer.forEach((b) => { zipBuffer.forEach((b) => {
if (!(size % bytesPerLine)) { if (!(size % bytesPerLine)) {
writeStream.write('\n'); writeStream.write('\n');
@@ -57,15 +68,19 @@ const writeFile = (relativeFilePath, buffer) => {
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ','); writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ',');
size++; size++;
}); });
if (size % bytesPerLine) { if (size % bytesPerLine) {
writeStream.write('\n'); writeStream.write('\n');
} }
writeStream.write('};\n\n'); writeStream.write('};\n\n');
fileInfo.push({ fileInfo.push({
uri: '/' + relativeFilePath.replace(sep, '/'), uri: '/' + relativeFilePath.replace(sep, '/'),
mimeType, mimeType,
variable, variable,
size size,
hash
}); });
// console.log(relativeFilePath + ' (size ' + size + ' bytes)'); // console.log(relativeFilePath + ' (size ' + size + ' bytes)');

Binary file not shown.

View File

@@ -4,7 +4,6 @@ import { ToastContainer, Slide } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.min.css'; import 'react-toastify/dist/ReactToastify.min.css';
import { localStorageDetector } from 'typesafe-i18n/detectors'; import { localStorageDetector } from 'typesafe-i18n/detectors';
import { FeaturesLoader } from './contexts/features';
import type { FC } from 'react'; import type { FC } from 'react';
import AppRouting from 'AppRouting'; import AppRouting from 'AppRouting';
import CustomTheme from 'CustomTheme'; import CustomTheme from 'CustomTheme';
@@ -27,9 +26,7 @@ const App: FC = () => {
return ( return (
<TypesafeI18n locale={detectedLocale}> <TypesafeI18n locale={detectedLocale}>
<CustomTheme> <CustomTheme>
<FeaturesLoader> <AppRouting />
<AppRouting />
</FeaturesLoader>
<ToastContainer <ToastContainer
position="bottom-left" position="bottom-left"
autoClose={3000} autoClose={3000}

View File

@@ -3,7 +3,6 @@ import { Box, Paper, Typography, MenuItem, TextField, Button } from '@mui/materi
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { FeaturesContext } from './contexts/features';
import type { ValidateFieldsError } from 'async-validator'; import type { ValidateFieldsError } from 'async-validator';
import type { Locales } from 'i18n/i18n-types'; import type { Locales } from 'i18n/i18n-types';
@@ -22,6 +21,7 @@ import ITflag from 'i18n/IT.svg';
import NLflag from 'i18n/NL.svg'; import NLflag from 'i18n/NL.svg';
import NOflag from 'i18n/NO.svg'; import NOflag from 'i18n/NO.svg';
import PLflag from 'i18n/PL.svg'; import PLflag from 'i18n/PL.svg';
import SKflag from 'i18n/SK.svg';
import SVflag from 'i18n/SV.svg'; import SVflag from 'i18n/SV.svg';
import TRflag from 'i18n/TR.svg'; import TRflag from 'i18n/TR.svg';
import { I18nContext } from 'i18n/i18n-react'; import { I18nContext } from 'i18n/i18n-react';
@@ -34,8 +34,6 @@ const SignIn: FC = () => {
const { LL, setLocale, locale } = useContext(I18nContext); const { LL, setLocale, locale } = useContext(I18nContext);
const { features } = useContext(FeaturesContext);
const [signInRequest, setSignInRequest] = useState<SignInRequest>({ const [signInRequest, setSignInRequest] = useState<SignInRequest>({
username: '', username: '',
password: '' password: ''
@@ -111,7 +109,6 @@ const SignIn: FC = () => {
})} })}
> >
<Typography variant="h4">{PROJECT_NAME}</Typography> <Typography variant="h4">{PROJECT_NAME}</Typography>
<Typography variant="subtitle2">{features.version}</Typography>
<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">
@@ -142,6 +139,10 @@ const SignIn: FC = () => {
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} /> <img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;PL &nbsp;PL
</MenuItem> </MenuItem>
<MenuItem key="sk" value="sk">
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;SK
</MenuItem>
<MenuItem key="sv" value="sv"> <MenuItem key="sv" value="sv">
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} /> <img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;SV &nbsp;SV

View File

@@ -1,5 +0,0 @@
import { alovaInstance } from './endpoints';
import type { Features } from 'types';
export const readFeatures = () => alovaInstance.Get<Features>('/rest/features');

View File

@@ -14,11 +14,9 @@ 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 DEflag from 'i18n/DE.svg';
import FRflag from 'i18n/FR.svg'; import FRflag from 'i18n/FR.svg';
import GBflag from 'i18n/GB.svg'; import GBflag from 'i18n/GB.svg';
@@ -26,8 +24,10 @@ import ITflag from 'i18n/IT.svg';
import NLflag from 'i18n/NL.svg'; import NLflag from 'i18n/NL.svg';
import NOflag from 'i18n/NO.svg'; import NOflag from 'i18n/NO.svg';
import PLflag from 'i18n/PL.svg'; import PLflag from 'i18n/PL.svg';
import SKflag from 'i18n/SK.svg';
import SVflag from 'i18n/SV.svg'; import SVflag from 'i18n/SV.svg';
import 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';
@@ -102,6 +102,10 @@ const LayoutAuthMenu: FC = () => {
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} /> <img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;PL &nbsp;PL
</MenuItem> </MenuItem>
<MenuItem key="sk" value="sk">
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;SK
</MenuItem>
<MenuItem key="sv" value="sv"> <MenuItem key="sv" value="sv">
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} /> <img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
&nbsp;SV &nbsp;SV

View File

@@ -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: React.ChangeEvent<HTMLInputElement>, path: string) => { const handleTabChange = (_event: any, path: string) => {
navigate(path); navigate(path);
}; };

View File

@@ -4,5 +4,9 @@ export const useRouterTab = () => {
const loc = useLocation().pathname; const loc = useLocation().pathname;
const routerTab = loc.substring(0, loc.lastIndexOf('/')) ? loc : false; const routerTab = loc.substring(0, loc.lastIndexOf('/')) ? loc : false;
// const routerTabPath = useResolvedPath(':tab');
// const routerTabPathMatch = useMatch(routerTabPath.pathname);
// const routerTab = routerTabPathMatch?.params?.tab || false;
return { routerTab } as const; return { routerTab } as const;
}; };

View File

@@ -50,8 +50,10 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
const progressText = () => { const progressText = () => {
if (uploading) { if (uploading) {
if (progress.total) { if (progress.total && progress.loaded) {
return LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%'; return progress.loaded <= progress.total
? LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%'
: LL.UPLOADING() + ': ' + Math.round((progress.total * 100) / progress.loaded) + '%';
} }
} }
return LL.UPLOAD_DROP_TEXT(); return LL.UPLOAD_DROP_TEXT();
@@ -83,7 +85,13 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
<Box width="100%" p={2}> <Box width="100%" p={2}>
<LinearProgress <LinearProgress
variant="determinate" variant="determinate"
value={progress.total === 0 ? 0 : Math.round((progress.loaded * 100) / progress.total)} value={
progress.total === 0 || progress.loaded === 0
? 0
: progress.loaded <= progress.total
? Math.round((progress.loaded * 100) / progress.total)
: Math.round((progress.total * 100) / progress.loaded)
}
/> />
</Box> </Box>
<Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}> <Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}>

View File

@@ -1,25 +0,0 @@
import { useRequest } from 'alova';
import { FeaturesContext } from '.';
import type { FC } from 'react';
import type { RequiredChildrenProps } from 'utils';
import * as FeaturesApi from 'api/features';
const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
const { data: features } = useRequest(FeaturesApi.readFeatures);
if (features) {
return (
<FeaturesContext.Provider
value={{
features
}}
>
{props.children}
</FeaturesContext.Provider>
);
}
};
export default FeaturesLoader;

View File

@@ -1,10 +0,0 @@
import { createContext } from 'react';
import type { Features } from 'types';
export interface FeaturesContextValue {
features: Features;
}
const FeaturesContextDefaultValue = {} as FeaturesContextValue;
export const FeaturesContext = createContext(FeaturesContextDefaultValue);

View File

@@ -1,2 +0,0 @@
export * from './context';
export { default as FeaturesLoader } from './FeaturesLoader';

View File

@@ -72,6 +72,7 @@ const MqttSettingsForm: FC = () => {
name="host" name="host"
label={LL.ADDRESS_OF(LL.BROKER())} label={LL.ADDRESS_OF(LL.BROKER())}
fullWidth fullWidth
multiline
variant="outlined" variant="outlined"
value={data.host} value={data.host}
onChange={updateFormValue} onChange={updateFormValue}
@@ -168,20 +169,24 @@ 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} />}
@@ -269,6 +274,7 @@ const MqttSettingsForm: FC = () => {
> >
<MenuItem value={0}>Home Assistant</MenuItem> <MenuItem value={0}>Home Assistant</MenuItem>
<MenuItem value={1}>Domoticz</MenuItem> <MenuItem value={1}>Domoticz</MenuItem>
<MenuItem value={2}>Domoticz (latest)</MenuItem>
</TextField> </TextField>
</Grid> </Grid>
<Grid item xs={12} sm={6} md={4}> <Grid item xs={12} sm={6} md={4}>

View File

@@ -15,8 +15,8 @@ import {
ListItemSecondaryAction, ListItemSecondaryAction,
ListItemText, ListItemText,
Typography, Typography,
InputAdornment, TextField,
TextField MenuItem
} from '@mui/material'; } from '@mui/material';
// eslint-disable-next-line import/named // eslint-disable-next-line import/named
import { updateState, useRequest } from 'alova'; import { updateState, useRequest } from 'alova';
@@ -43,7 +43,7 @@ import {
} from 'components'; } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { numberValue, updateValueDirty, useRest } from 'utils'; import { updateValueDirty, useRest } from 'utils';
import { validate } from 'validators'; import { validate } from 'validators';
import { createNetworkSettingsValidator } from 'validators/network'; import { createNetworkSettingsValidator } from 'validators/network';
@@ -88,7 +88,7 @@ const WiFiSettingsForm: FC = () => {
static_ip_config: false, static_ip_config: false,
enableIPv6: false, enableIPv6: false,
bandwidth20: false, bandwidth20: false,
tx_power: 20, tx_power: 0,
nosleep: false, nosleep: false,
enableMDNS: true, enableMDNS: true,
enableCORS: false, enableCORS: false,
@@ -196,20 +196,29 @@ const WiFiSettingsForm: FC = () => {
margin="normal" margin="normal"
/> />
)} )}
<ValidatedTextField <TextField
fieldErrors={fieldErrors}
name="tx_power" name="tx_power"
label={LL.TX_POWER()} label={LL.TX_POWER()}
InputProps={{
endAdornment: <InputAdornment position="end">dBm</InputAdornment>
}}
fullWidth fullWidth
variant="outlined" variant="outlined"
value={numberValue(data.tx_power)} value={data.tx_power}
onChange={updateFormValue} onChange={updateFormValue}
type="number"
margin="normal" margin="normal"
/> select
>
<MenuItem value={0}>Auto</MenuItem>
<MenuItem value={78}>19.5 dBm</MenuItem>
<MenuItem value={76}>19 dBm</MenuItem>
<MenuItem value={74}>18.5 dBm</MenuItem>
<MenuItem value={68}>17 dBm</MenuItem>
<MenuItem value={60}>15 dBm</MenuItem>
<MenuItem value={52}>13 dBm</MenuItem>
<MenuItem value={44}>11 dBm</MenuItem>
<MenuItem value={34}>8.5 dBm</MenuItem>
<MenuItem value={28}>7 dBm</MenuItem>
<MenuItem value={20}>5 dBm</MenuItem>
<MenuItem value={8}>2 dBm</MenuItem>
</TextField>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="nosleep" checked={data.nosleep} onChange={updateFormValue} />} control={<Checkbox name="nosleep" checked={data.nosleep} onChange={updateFormValue} />}
label={LL.NETWORK_DISABLE_SLEEP()} label={LL.NETWORK_DISABLE_SLEEP()}
@@ -250,10 +259,12 @@ const WiFiSettingsForm: FC = () => {
margin="normal" margin="normal"
/> />
)} )}
<BlockFormControlLabel {data.enableIPv6 !== undefined && (
control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />} <BlockFormControlLabel
label={LL.NETWORK_ENABLE_IPV6()} control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />}
/> label={LL.NETWORK_ENABLE_IPV6()}
/>
)}
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="static_ip_config" checked={data.static_ip_config} onChange={updateFormValue} />} control={<Checkbox name="static_ip_config" checked={data.static_ip_config} onChange={updateFormValue} />}
label={LL.NETWORK_FIXED_IP()} label={LL.NETWORK_FIXED_IP()}
@@ -313,7 +324,7 @@ const WiFiSettingsForm: FC = () => {
</> </>
)} )}
{restartNeeded && ( {restartNeeded && (
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}> <MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}> <Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
{LL.RESTART()} {LL.RESTART()}
</Button> </Button>

View File

@@ -1,5 +1,6 @@
import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import DnsIcon from '@mui/icons-material/Dns'; import DnsIcon from '@mui/icons-material/Dns';
import GiteIcon from '@mui/icons-material/Gite';
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import RouterIcon from '@mui/icons-material/Router'; import RouterIcon from '@mui/icons-material/Router';
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
@@ -115,6 +116,15 @@ const NetworkStatusForm: FC = () => {
<ListItemText primary="Status" secondary={networkStatus(data)} /> <ListItemText primary="Status" secondary={networkStatus(data)} />
</ListItem> </ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListItem>
<ListItemAvatar>
<Avatar sx={{ bgcolor: networkStatusHighlight(data, theme) }}>
<GiteIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Hostname" secondary={data.hostname} />
</ListItem>
<Divider variant="inset" component="li" />
{isWiFi(data) && ( {isWiFi(data) && (
<> <>
<ListItem> <ListItem>

View File

@@ -37,7 +37,8 @@ const GenerateToken: FC<GenerateTokenProps> = ({ username, onClose }) => {
if (open) { if (open) {
void generateToken(); void generateToken();
} }
}, [open, generateToken]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]);
return ( return (
<Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm"> <Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm">

View File

@@ -1,6 +1,7 @@
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';
@@ -9,7 +10,6 @@ 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,
@@ -29,7 +29,6 @@ import {
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { FeaturesContext } from '../../contexts/features';
import RestartMonitor from './RestartMonitor'; import RestartMonitor from './RestartMonitor';
import SystemStatusVersionDialog from './SystemStatusVersionDialog'; import SystemStatusVersionDialog from './SystemStatusVersionDialog';
import type { FC } from 'react'; import type { FC } from 'react';
@@ -54,8 +53,6 @@ const SystemStatusForm: FC = () => {
const [restarting, setRestarting] = useState<boolean>(); const [restarting, setRestarting] = useState<boolean>();
const [versionDialogOpen, setVersionDialogOpen] = useState<boolean>(false); const [versionDialogOpen, setVersionDialogOpen] = useState<boolean>(false);
const { features } = useContext(FeaturesContext);
const { send: restartCommand } = useRequest(SystemApi.restart(), { const { send: restartCommand } = useRequest(SystemApi.restart(), {
immediate: false immediate: false
}); });
@@ -200,15 +197,6 @@ 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>
@@ -221,10 +209,33 @@ const SystemStatusForm: FC = () => {
<ListItem> <ListItem>
<ListItemAvatar> <ListItemAvatar>
<Avatar> <Avatar>
<ShowChartIcon /> <DevicesIcon />
</Avatar> </Avatar>
</ListItemAvatar> </ListItemAvatar>
<ListItemText primary={LL.CPU_FREQ()} secondary={data.cpu_freq_mhz + ' MHz'} /> <ListItemText primary="SDK" secondary={data.arduino_version + ' / ESP-IDF ' + data.sdk_version} />
</ListItem>
<Divider variant="inset" component="li" />
<ListItem>
<ListItemAvatar>
<Avatar>
<DeveloperBoardIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="CPU"
secondary={
data.esp_platform +
'/' +
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>
@@ -277,7 +288,9 @@ const SystemStatusForm: FC = () => {
</ListItemAvatar> </ListItemAvatar>
<ListItemText <ListItemText
primary={LL.APPSIZE()} primary={LL.APPSIZE()}
secondary={formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'} secondary={
data.partition + ': ' + formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'
}
/> />
</ListItem> </ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -339,7 +352,7 @@ const SystemStatusForm: FC = () => {
open={versionDialogOpen} open={versionDialogOpen}
onClose={() => setVersionDialogOpen(false)} onClose={() => setVersionDialogOpen(false)}
version={data.emsesp_version} version={data.emsesp_version}
platform={features.platform} platform={data.esp_platform}
/> />
)} )}
</SectionContent> </SectionContent>

View File

@@ -19,7 +19,7 @@ const UploadFileForm: FC = () => {
const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), { const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), {
immediate: false immediate: false
}); });
const { send: getCustomizations, onSuccess: onSuccessgetCustomizations } = useRequest(EMSESP.getCustomizations(), { const { send: getCustomizations, onSuccess: onSuccessGetCustomizations } = useRequest(EMSESP.getCustomizations(), {
immediate: false immediate: false
}); });
const { send: getEntities, onSuccess: onSuccessGetEntities } = useRequest(EMSESP.getEntities(), { const { send: getEntities, onSuccess: onSuccessGetEntities } = useRequest(EMSESP.getEntities(), {
@@ -28,7 +28,7 @@ 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: getInfo, onSuccess: onSuccessGetInfo } = useRequest((data) => EMSESP.API(data), { const { send: getAPI, onSuccess: onGetAPI } = useRequest((data) => EMSESP.API(data), {
immediate: false immediate: false
}); });
@@ -71,26 +71,26 @@ const UploadFileForm: FC = () => {
type: 'text/plain' type: 'text/plain'
}) })
); );
anchor.download = 'emsesp_' + endpoint + '.json'; anchor.download = 'emsesp_' + endpoint;
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'); saveFile(event.data, 'settings.json');
}); });
onSuccessgetCustomizations((event) => { onSuccessGetCustomizations((event) => {
saveFile(event.data, 'customizations'); saveFile(event.data, 'customizations.json');
}); });
onSuccessGetEntities((event) => { onSuccessGetEntities((event) => {
saveFile(event.data, 'entities'); saveFile(event.data, 'entities.json');
}); });
onSuccessGetSchedule((event) => { onSuccessGetSchedule((event) => {
saveFile(event.data, 'schedule'); saveFile(event.data, 'schedule.json');
}); });
onSuccessGetInfo((event) => { onGetAPI((event) => {
saveFile(event.data, 'info'); saveFile(event.data, event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt');
}); });
const downloadSettings = async () => { const downloadSettings = async () => {
@@ -112,13 +112,17 @@ const UploadFileForm: FC = () => {
}; };
const downloadSchedule = async () => { const downloadSchedule = async () => {
await getSchedule().catch((error) => { await getSchedule()
toast.error(error.message); .catch((error) => {
}); toast.error(error.message);
})
.finally(() => {
toast.info(LL.DOWNLOAD_SUCCESSFUL());
});
}; };
const downloadInfo = async () => { const callAPI = async (device: string, entity: string) => {
await getInfo({ device: 'system', entity: 'info', id: 0 }).catch((error) => { await getAPI({ device, entity, id: 0 }).catch((error) => {
toast.error(error.message); toast.error(error.message);
}); });
}; };
@@ -132,7 +136,8 @@ const UploadFileForm: FC = () => {
<Typography variant="body2"> <Typography variant="body2">
{LL.UPLOAD_TEXT()} {LL.UPLOAD_TEXT()}
<br /> <br />
{LL.RESTART_TEXT()}. <br />
{LL.RESTART_TEXT(1)}.
</Typography> </Typography>
</Box> </Box>
{md5 && ( {md5 && (
@@ -143,8 +148,34 @@ 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: 2, pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)} {LL.DOWNLOAD(0)}&nbsp;{LL.SUPPORT_INFORMATION(1)}
</Typography>
<Box color="warning.main">
<Typography mb={1} variant="body2">
{LL.HELP_INFORMATION_4()}
</Typography>
</Box>
<Button
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'info')}
>
{LL.SUPPORT_INFORMATION(0)}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'allvalues')}
>
All Values
</Button>
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)}&nbsp;{LL.SETTINGS(1)}
</Typography> </Typography>
<Box color="warning.main"> <Box color="warning.main">
<Typography mb={1} variant="body2"> <Typography mb={1} variant="body2">
@@ -179,14 +210,6 @@ const UploadFileForm: FC = () => {
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSchedule}> <Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSchedule}>
{LL.SCHEDULE(0)} {LL.SCHEDULE(0)}
</Button> </Button>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD(0)}&nbsp;{LL.SUPPORT_INFORMATION()}
</Typography>
</Box>
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadInfo}>
{LL.SUPPORT_INFORMATION()}
</Button>
</> </>
)} )}
</> </>

View File

@@ -0,0 +1 @@
<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>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -191,16 +191,14 @@ const de: Translation = {
THE_LATEST: 'Die neueste', THE_LATEST: 'Die neueste',
OFFICIAL: 'offizielle', OFFICIAL: 'offizielle',
DEVELOPMENT: 'Entwicklungs', DEVELOPMENT: 'Entwicklungs',
RELEASE_IS: 'release ist', // TODO translate RELEASE_IS: 'Release ist',
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 (Genutzt / Frei)', APPSIZE: 'Programm (Partition: 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',
@@ -230,7 +228,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',
@@ -309,7 +307,7 @@ const de: Translation = {
LEAVE: 'Verlassen', LEAVE: 'Verlassen',
SCHEDULER: 'Planer', SCHEDULER: 'Planer',
SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern', SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern',
SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate SCHEDULER_HELP_2: '00:00 aktiviert einmalige Ausführung am Start',
SCHEDULE: 'Zeitplan', SCHEDULE: 'Zeitplan',
TIME: 'Zeit', TIME: 'Zeit',
TIMER: 'Timer', TIMER: 'Timer',
@@ -318,12 +316,13 @@ const de: Translation = {
SCHEDULE_TIMER_2: 'jede Minute', SCHEDULE_TIMER_2: 'jede Minute',
SCHEDULE_TIMER_3: 'jede Stunde', SCHEDULE_TIMER_3: 'jede Stunde',
CUSTOM_ENTITIES: 'Individuelle Entitäten', CUSTOM_ENTITIES: 'Individuelle Entitäten',
ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus', ENTITIES_HELP_1: 'Definition eigener EMS-Werte oder dynamischer Variablen',
ENTITIES_UPDATED: 'Entitäten gespeichert', ENTITIES_UPDATED: 'Entitäten gespeichert',
WRITEABLE: 'Schreibbar', WRITEABLE: 'Schreibbar',
SHOWING: 'Anzeigen von', SHOWING: 'Anzeigen von',
SEARCH: 'Suche', SEARCH: 'Suche',
CERT: 'TLS Zertifikat (Freilassen um TLS zu deaktivieren)', CERT: 'TLS Zertifikat (Freilassen für unsichere Verbindung)',
ENABLE_TLS: 'Aktiviere TLS',
ON: 'An', ON: 'An',
OFF: 'Aus', OFF: 'Aus',
POLARITY: 'Polarität', POLARITY: 'Polarität',

View File

@@ -63,7 +63,7 @@ const en: Translation = {
FREQ: 'Frequency', FREQ: 'Frequency',
DUTY_CYCLE: 'Duty Cycle', DUTY_CYCLE: 'Duty Cycle',
UNIT: 'UoM', UNIT: 'UoM',
STARTVALUE: 'Start value', STARTVALUE: 'Start Value',
WARN_GPIO: 'Warning: be careful when assigning a GPIO!', WARN_GPIO: 'Warning: be careful when assigning a GPIO!',
EDIT: 'Edit', EDIT: 'Edit',
SENSOR: 'Sensor', SENSOR: 'Sensor',
@@ -169,7 +169,7 @@ 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 system information for a faster response when reporting an issue', HELP_INFORMATION_4: 'Remember to download and attach your support 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!',
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
@@ -196,11 +196,10 @@ 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 (Used / Free)', APPSIZE: 'Application (Partition: 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',
@@ -318,12 +317,13 @@ const en: Translation = {
SCHEDULE_TIMER_2: 'every minute', SCHEDULE_TIMER_2: 'every minute',
SCHEDULE_TIMER_3: 'every hour', SCHEDULE_TIMER_3: 'every hour',
CUSTOM_ENTITIES: 'Custom Entities', CUSTOM_ENTITIES: 'Custom Entities',
ENTITIES_HELP_1: 'Fetch custom entities from the EMS bus', ENTITIES_HELP_1: 'Define custom EMS entities or dynamic user variables',
ENTITIES_UPDATED: 'Entities Updated', ENTITIES_UPDATED: 'Entities Updated',
WRITEABLE: 'Writeable', WRITEABLE: 'Writeable',
SHOWING: 'Showing', SHOWING: 'Showing',
SEARCH: 'Search', SEARCH: 'Search',
CERT: 'TLS root certificate (leave blank to disable TLS)', CERT: 'TLS root certificate (leave blank for insecure)',
ENABLE_TLS: 'Enable TLS',
ON: 'On', ON: 'On',
OFF: 'Off', OFF: 'Off',
POLARITY: 'Polarity', POLARITY: 'Polarity',

View File

@@ -169,7 +169,7 @@ 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 !',
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
@@ -194,13 +194,11 @@ 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 (Utilisée / Libre)', APPSIZE: 'Application (Partition: 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',
@@ -323,7 +321,8 @@ 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 to disable TLS)', // TODO translate CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
ENABLE_TLS: 'Activer TLS',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -171,7 +171,7 @@ 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!',
UPLOAD: 'Carica', UPLOAD: 'Carica',
DOWNLOAD: 'Scarica', DOWNLOAD: 'Scarica',
@@ -196,13 +196,11 @@ 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 (Usata / Libera)', APPSIZE: 'Applicazione (Partizione: 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',
@@ -320,12 +318,13 @@ const it: Translation = {
SCHEDULE_TIMER_2: 'Ogni minuto', SCHEDULE_TIMER_2: 'Ogni minuto',
SCHEDULE_TIMER_3: 'Ogni ora', SCHEDULE_TIMER_3: 'Ogni ora',
CUSTOM_ENTITIES: 'Entità personalizzate', CUSTOM_ENTITIES: 'Entità personalizzate',
ENTITIES_HELP_1: 'Recupera entità personalizzate dal BUS EMS', ENTITIES_HELP_1: 'Recupera entità personalizzate dal BUS EMS', // TODO translate
ENTITIES_UPDATED: 'Entità aggiornate', ENTITIES_UPDATED: 'Entità aggiornate',
WRITEABLE: 'Scrivibile', WRITEABLE: 'Scrivibile',
SHOWING: 'Visualizza', SHOWING: 'Visualizza',
SEARCH: 'Ricerca', SEARCH: 'Ricerca',
CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
ENABLE_TLS: 'Abilita TLS',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -169,7 +169,7 @@ 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!',
UPLOAD: 'Upload', UPLOAD: 'Upload',
DOWNLOAD: '{{D|d|d}}ownload', DOWNLOAD: '{{D|d|d}}ownload',
@@ -194,13 +194,11 @@ 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 (Used / Free)', APPSIZE: 'Application (Partition: 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',
@@ -318,12 +316,13 @@ const nl: Translation = {
SCHEDULE_TIMER_2: 'elke minuut', SCHEDULE_TIMER_2: 'elke minuut',
SCHEDULE_TIMER_3: 'elke huur', SCHEDULE_TIMER_3: 'elke huur',
CUSTOM_ENTITIES: 'Aangepaste Entiteiten', CUSTOM_ENTITIES: 'Aangepaste Entiteiten',
ENTITIES_HELP_1: 'Aangepaste entiteiten ophalen uit de EMS-bus', ENTITIES_HELP_1: 'Aangepaste entiteiten ophalen uit de EMS-bus', // TODO translate
ENTITIES_UPDATED: 'Entiteiten bijgewerkt', ENTITIES_UPDATED: 'Entiteiten bijgewerkt',
WRITEABLE: 'Beschrijfbare', WRITEABLE: 'Beschrijfbare',
SHOWING: 'Tonen', SHOWING: 'Tonen',
SEARCH: 'Zoek', SEARCH: 'Zoek',
CERT: 'TLS rootcertificaat (laat leeg om TLS uit te schakelen)', CERT: 'TLS rootcertificaat (laat leeg om TLS-insecure)', // TODO translate
ENABLE_TLS: 'Activeer TLS',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -169,7 +169,7 @@ 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!',
UPLOAD: 'Opplasning', UPLOAD: 'Opplasning',
DOWNLOAD: '{{N|n|n}}edlasting', DOWNLOAD: '{{N|n|n}}edlasting',
@@ -194,13 +194,11 @@ 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 (Brukt / Ledig)', APPSIZE: 'Applikasjon (Partition: 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',
@@ -323,7 +321,8 @@ 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 to disable TLS)', // TODO translate CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
ENABLE_TLS: 'Aktiviser TLS',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -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: 'ustawienia', SETTINGS: 'ustawie{{nia|ń|}}',
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,7 @@ 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 boiler z wymuszonym wyłączonym grzaniem', 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 +146,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ć zrestartowany.', RESTART_TEXT: 'Aby zastosować wprowadzone zmiany, interfejs EMS-ESP {{musi zostać|zostanie|}} uruchomiony ponowni{{e.|e|}}',
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, dostosuj opcje lub kliknij by zmienić nazwę encji.', CUSTOMIZATIONS_HELP_1: 'Wybierz urządzenie EMS, a następnie dostosuj opcje lub kliknij na nazwie encji by tę nazwę zmienić',
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,12 +164,12 @@ 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: 'Informacje dotyczące wsparcia', SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
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 dołączyć informacji o swoim systemie!', HELP_INFORMATION_4: 'Zgłaszając problem, nie zapomnij pobrać i dołączyć informacji o swoim systemie!',
HELP_INFORMATION_5: '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!',
UPLOAD: 'Wysyłanie', UPLOAD: 'Wysyłanie',
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}', DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
@@ -194,21 +194,19 @@ 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 (wykorzystane / wolne)', APPSIZE: 'Aplikacja (partycja: 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. Uważaj jeśli udostępniasz plik z ustawieniami, ponieważ zawiera on hasła oraz inne wrażliwe informacje!', DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uwaga! Plik z ustawieniami zawiera hasła oraz inne wrażliwe informacje systemowe! Nie udostepniaj go pochopnie!',
UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji (.md5).', UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji z sumą kontrolną (.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!',
@@ -318,12 +316,13 @@ const pl: BaseTranslation = {
SCHEDULE_TIMER_2: 'co minutę', SCHEDULE_TIMER_2: 'co minutę',
SCHEDULE_TIMER_3: 'co godzinę', SCHEDULE_TIMER_3: 'co godzinę',
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.', // TODO translate
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 zby wyłączyć TLS)', CERT: 'Certyfikat główny TLS (pozostaw puste dla TLS-insecure)',
ENABLE_TLS: 'Włącz wsparcie dla TLS',
ON: 'włączony', ON: 'włączony',
OFF: 'wyłączony', OFF: 'wyłączony',
POLARITY: 'Typ przekaźnika', POLARITY: 'Typ przekaźnika',

View File

@@ -0,0 +1,335 @@
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', // TODO translate
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;

View File

@@ -194,13 +194,11 @@ 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 (Använt / Ledigt)', APPSIZE: 'Applikationer (Partition: 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',
@@ -323,7 +321,8 @@ 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 to disable TLS)', // TODO translate CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
ENABLE_TLS: 'Aktivera TLS',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -194,13 +194,11 @@ 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 (Kullanılmış / Boş)', APPSIZE: 'Uygulama (Bölme: 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',
@@ -323,7 +321,8 @@ 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 to disable TLS)', // TODO translate CERT: 'TLS root certificate (leave blank for insecure)',
ENABLE_TLS: 'TLS deveye al',
ON: 'On', // TODO translate ON: 'On', // TODO translate
OFF: 'Off', // TODO translate OFF: 'Off', // TODO translate
POLARITY: 'Polarity', // TODO translate POLARITY: 'Polarity', // TODO translate

View File

@@ -94,8 +94,14 @@ const DashboardDevices: FC = () => {
}, []); }, []);
const leftOffset = () => { const leftOffset = () => {
const left = document.getElementById('devices-window')?.getBoundingClientRect().left; const devicesWindow = document.getElementById('devices-window');
const right = document.getElementById('devices-window')?.getBoundingClientRect().right; if (!devicesWindow) {
return 0;
}
const clientRect = devicesWindow.getBoundingClientRect();
const left = clientRect.left;
const right = clientRect.right;
if (!left || !right) { if (!left || !right) {
return 0; return 0;
@@ -416,37 +422,39 @@ const DashboardDevices: FC = () => {
const renderCoreData = () => ( const renderCoreData = () => (
<IconContext.Provider value={{ color: 'lightblue', size: '24', style: { verticalAlign: 'middle' } }}> <IconContext.Provider value={{ color: 'lightblue', size: '24', style: { verticalAlign: 'middle' } }}>
{!coreData.connected && <MessageBox my={2} level="error" message={LL.EMS_BUS_WARNING()} />} {!coreData.connected && <MessageBox my={2} level="error" message={LL.EMS_BUS_WARNING()} />}
{coreData.connected && coreData.devices.length === 0 && ( {/* {coreData.connected && coreData.devices.length === 0 && (
<MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} /> <MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} />
)} )} */}
<Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}> {coreData.connected && (
{(tableList: any) => ( <Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}>
<> {(tableList: any) => (
<Header> <>
<HeaderRow> <Header>
<HeaderCell stiff /> <HeaderRow>
<HeaderCell resize>{LL.DESCRIPTION()}</HeaderCell> <HeaderCell stiff />
<HeaderCell stiff>{LL.TYPE(0)}</HeaderCell> <HeaderCell resize>{LL.DESCRIPTION()}</HeaderCell>
</HeaderRow> <HeaderCell stiff>{LL.TYPE(0)}</HeaderCell>
</Header> </HeaderRow>
<Body> </Header>
{tableList.map((device: Device) => ( <Body>
<Row key={device.id} item={device}> {tableList.map((device: Device) => (
<Cell stiff> <Row key={device.id} item={device}>
<DeviceIcon type_id={device.t} /> <Cell stiff>
</Cell> <DeviceIcon type_id={device.t} />
<Cell> </Cell>
{device.n} <Cell>
<span style={{ color: 'lightblue' }}>&nbsp;&nbsp;({device.e})</span> {device.n}
</Cell> <span style={{ color: 'lightblue' }}>&nbsp;&nbsp;({device.e})</span>
<Cell stiff>{device.tn}</Cell> </Cell>
</Row> <Cell stiff>{device.tn}</Cell>
))} </Row>
</Body> ))}
</> </Body>
)} </>
</Table> )}
</Table>
)}
</IconContext.Provider> </IconContext.Provider>
); );

View File

@@ -26,7 +26,7 @@ import type { ValidateFieldsError } from 'async-validator';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { ValidatedTextField } from 'components'; import { ValidatedTextField } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { updateValue } from 'utils'; import { updateValue, numberValue } from 'utils';
import { validate } from 'validators'; import { validate } from 'validators';
@@ -133,7 +133,7 @@ const DashboardDevicesDialog = ({
fieldErrors={fieldErrors} fieldErrors={fieldErrors}
name="v" name="v"
label={LL.VALUE(1)} label={LL.VALUE(1)}
value={Math.round(editItem.v * 10) / 10} value={numberValue(Math.round(editItem.v * 10) / 10)}
autoFocus autoFocus
disabled={!writeable} disabled={!writeable}
type="number" type="number"

View File

@@ -262,7 +262,7 @@ const DashboardSensors: FC = () => {
setSelectedAnalogSensor({ setSelectedAnalogSensor({
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100), id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
n: '', n: '',
g: 40, g: 21, // default GPIO 21 which is safe for all platforms
u: 0, u: 0,
v: 0, v: 0,
o: 0, o: 0,

View File

@@ -182,7 +182,7 @@ const DashboardSensorsAnalogDialog = ({
<Grid item xs={4}> <Grid item xs={4}>
<TextField <TextField
name="o" name="o"
label={LL.VALUE(0)} label={LL.VALUE(1)}
value={numberValue(editItem.o)} value={numberValue(editItem.o)}
fullWidth fullWidth
type="number" type="number"
@@ -197,7 +197,7 @@ const DashboardSensorsAnalogDialog = ({
<Grid item xs={4}> <Grid item xs={4}>
<TextField <TextField
name="o" name="o"
label={LL.VALUE(0)} label={LL.VALUE(1)}
value={numberValue(editItem.o)} value={numberValue(editItem.o)}
fullWidth fullWidth
select select

View File

@@ -1,20 +1,45 @@
import CommentIcon from '@mui/icons-material/CommentTwoTone'; import CommentIcon from '@mui/icons-material/CommentTwoTone';
import EastIcon from '@mui/icons-material/East'; import EastIcon from '@mui/icons-material/East';
import DownloadIcon from '@mui/icons-material/GetApp';
import GitHubIcon from '@mui/icons-material/GitHub'; import GitHubIcon from '@mui/icons-material/GitHub';
import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone'; import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
import { Box, List, ListItem, ListItemAvatar, ListItemText, Link, Typography } from '@mui/material'; 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 { SectionContent, 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();
useLayoutTitle(LL.HELP_OF('')); useLayoutTitle(LL.HELP_OF(''));
const uploadURL = window.location.origin + '/system/upload'; const { send: getAPI, onSuccess: onGetAPI } = useRequest((data) => EMSESP.API(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].device + '_' + event.sendArgs[0].entity + '.txt';
anchor.click();
URL.revokeObjectURL(anchor.href);
toast.info(LL.DOWNLOAD_SUCCESSFUL());
});
const callAPI = async (device: string, entity: string) => {
await getAPI({ device, entity, id: 0 }).catch((error) => {
toast.error(error.message);
});
};
return ( return (
<SectionContent title={LL.SUPPORT_INFORMATION()} titleGutter> <SectionContent title={LL.SUPPORT_INFORMATION(0)} titleGutter>
<List> <List>
<ListItem> <ListItem>
<ListItemAvatar> <ListItemAvatar>
@@ -55,15 +80,28 @@ const Help: FC = () => {
{LL.CLICK_HERE()} {LL.CLICK_HERE()}
</Link> </Link>
<br /> <br />
<i>({LL.HELP_INFORMATION_4()}</i>&nbsp;
<Link href={uploadURL} color="primary">
{LL.UPLOAD()}
</Link>
)
</ListItemText> </ListItemText>
</ListItem> </ListItem>
</List> </List>
<Box color="warning.main">
<Typography mb={1} variant="body2">
{LL.HELP_INFORMATION_4()}
</Typography>
</Box>
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callAPI('system', 'info')}>
{LL.SUPPORT_INFORMATION(0)}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'allvalues')}
>
All Values
</Button>
<Box border={1} p={1} mt={4} color="orange"> <Box border={1} p={1} mt={4} color="orange">
<Typography align="center" variant="subtitle1" color="orange"> <Typography align="center" variant="subtitle1" color="orange">
<b>{LL.HELP_INFORMATION_5()}</b> <b>{LL.HELP_INFORMATION_5()}</b>
@@ -73,7 +111,7 @@ const Help: FC = () => {
{'github.com/emsesp/EMS-ESP32'} {'github.com/emsesp/EMS-ESP32'}
</Link> </Link>
</Typography> </Typography>
<Typography color="white" align="center"> <Typography color="white" variant="subtitle2" align="center">
@proddy @MichaelDvP @proddy @MichaelDvP
</Typography> </Typography>
</Box> </Box>

View File

@@ -2,8 +2,8 @@ import { Tab } from '@mui/material';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import SettingsApplication from './SettingsApplication'; import SettingsApplication from './SettingsApplication';
import SettingsCustomEntities from './SettingsCustomEntities';
import SettingsCustomization from './SettingsCustomization'; import SettingsCustomization from './SettingsCustomization';
import SettingsEntities from './SettingsEntities';
import SettingsScheduler from './SettingsScheduler'; import SettingsScheduler from './SettingsScheduler';
import type { FC } from 'react'; import type { FC } from 'react';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components'; import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
@@ -27,7 +27,7 @@ const Settings: FC = () => {
<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={<SettingsCustomEntities />} />
<Route path="*" element={<Navigate replace to="/settings/application" />} /> <Route path="*" element={<Navigate replace to="/settings/application" />} />
</Routes> </Routes>
</> </>

View File

@@ -384,6 +384,7 @@ 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>
@@ -644,7 +645,7 @@ const SettingsApplication: FC = () => {
</Grid> </Grid>
)} )}
{restartNeeded && ( {restartNeeded && (
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}> <MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}> <Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
{LL.RESTART()} {LL.RESTART()}
</Button> </Button>

View File

@@ -1,5 +1,7 @@
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 EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import RefreshIcon from '@mui/icons-material/Refresh';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { Button, Typography, Box } from '@mui/material'; import { Button, Typography, Box } from '@mui/material';
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';
@@ -11,7 +13,7 @@ import { useBlocker } from 'react-router-dom';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import SettingsEntitiesDialog from './SettingsEntitiesDialog'; import SettingsCustomEntitiesDialog from './SettingsCustomEntitiesDialog';
import * as EMSESP from './api'; import * as EMSESP from './api';
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types'; import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
import { entityItemValidation } from './validators'; import { entityItemValidation } from './validators';
@@ -21,7 +23,7 @@ import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'componen
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
const SettingsEntities: FC = () => { const SettingsCustomEntities: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [numChanges, setNumChanges] = useState<number>(0); const [numChanges, setNumChanges] = useState<number>(0);
const blocker = useBlocker(numChanges !== 0); const blocker = useBlocker(numChanges !== 0);
@@ -43,6 +45,7 @@ const SettingsEntities: FC = () => {
function hasEntityChanged(ei: EntityItem) { function hasEntityChanged(ei: EntityItem) {
return ( return (
ei.id !== ei.o_id || ei.id !== ei.o_id ||
ei.ram !== ei.o_ram ||
(ei?.name || '') !== (ei?.o_name || '') || (ei?.name || '') !== (ei?.o_name || '') ||
ei.device_id !== ei.o_device_id || ei.device_id !== ei.o_device_id ||
ei.type_id !== ei.o_type_id || ei.type_id !== ei.o_type_id ||
@@ -51,7 +54,8 @@ const SettingsEntities: FC = () => {
ei.factor !== ei.o_factor || ei.factor !== ei.o_factor ||
ei.value_type !== ei.o_value_type || ei.value_type !== ei.o_value_type ||
ei.writeable !== ei.o_writeable || ei.writeable !== ei.o_writeable ||
ei.deleted !== ei.o_deleted ei.deleted !== ei.o_deleted ||
(ei.value || '') !== (ei.o_value || '')
); );
} }
@@ -118,6 +122,7 @@ const SettingsEntities: FC = () => {
.filter((ei) => !ei.deleted) .filter((ei) => !ei.deleted)
.map((condensed_ei) => ({ .map((condensed_ei) => ({
id: condensed_ei.id, id: condensed_ei.id,
ram: condensed_ei.ram,
name: condensed_ei.name, name: condensed_ei.name,
device_id: condensed_ei.device_id, device_id: condensed_ei.device_id,
type_id: condensed_ei.type_id, type_id: condensed_ei.type_id,
@@ -125,7 +130,8 @@ const SettingsEntities: FC = () => {
factor: condensed_ei.factor, factor: condensed_ei.factor,
uom: condensed_ei.uom, uom: condensed_ei.uom,
writeable: condensed_ei.writeable, writeable: condensed_ei.writeable,
value_type: condensed_ei.value_type value_type: condensed_ei.value_type,
value: condensed_ei.value
})) }))
}) })
.then(() => { .then(() => {
@@ -173,14 +179,16 @@ const SettingsEntities: FC = () => {
setSelectedEntityItem({ setSelectedEntityItem({
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100), id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
name: '', name: '',
device_id: '', ram: 0,
type_id: '', device_id: '0',
type_id: '0',
offset: 0, offset: 0,
factor: 1, factor: 1,
uom: 0, uom: 0,
value_type: 0, value_type: 0,
writeable: false, writeable: false,
deleted: false deleted: false,
value: ''
}); });
setDialogOpen(true); setDialogOpen(true);
}; };
@@ -212,18 +220,21 @@ const SettingsEntities: FC = () => {
<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>{LL.OFFSET()}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1) + ' ' + LL.TYPE(1)}</HeaderCell> <HeaderCell stiff>{LL.TYPE(1)}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell> <HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
</HeaderRow> </HeaderRow>
</Header> </Header>
<Body> <Body>
{tableList.map((ei: EntityItem) => ( {tableList.map((ei: EntityItem) => (
<Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}> <Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}>
<Cell>{ei.name}</Cell> <Cell>
<Cell>{showHex(ei.device_id as number, 2)}</Cell> {ei.name}&nbsp;
<Cell>{showHex(ei.type_id as number, 3)}</Cell> {ei.writeable && <EditOutlinedIcon color="primary" sx={{ fontSize: 12 }} />}
<Cell>{ei.offset}</Cell> </Cell>
<Cell>{DeviceValueTypeNames[ei.value_type]}</Cell> <Cell>{ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}</Cell>
<Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
<Cell>{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}</Cell>
<Cell>{formatValue(ei.value, ei.uom)}</Cell> <Cell>{formatValue(ei.value, ei.uom)}</Cell>
</Row> </Row>
))} ))}
@@ -244,7 +255,7 @@ const SettingsEntities: FC = () => {
{renderEntity()} {renderEntity()}
{selectedEntityItem && ( {selectedEntityItem && (
<SettingsEntitiesDialog <SettingsCustomEntitiesDialog
open={dialogOpen} open={dialogOpen}
creating={creating} creating={creating}
onClose={onDialogClose} onClose={onDialogClose}
@@ -274,7 +285,10 @@ const SettingsEntities: FC = () => {
</Box> </Box>
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box flexWrap="nowrap" whiteSpace="nowrap">
<ButtonRow> <ButtonRow>
<Button startIcon={<AddIcon />} variant="outlined" color="secondary" onClick={addEntityItem}> <Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={fetchEntities}>
{LL.REFRESH()}
</Button>
<Button startIcon={<AddIcon />} variant="outlined" color="primary" onClick={addEntityItem}>
{LL.ADD(0)} {LL.ADD(0)}
</Button> </Button>
</ButtonRow> </ButtonRow>
@@ -284,4 +298,4 @@ const SettingsEntities: FC = () => {
); );
}; };
export default SettingsEntities; export default SettingsCustomEntities;

View File

@@ -0,0 +1,284 @@
import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import {
Box,
Button,
Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
InputAdornment,
MenuItem,
TextField
} from '@mui/material';
import { useEffect, useState } from 'react';
import { DeviceValueUOM_s, DeviceValueType } from './types';
import type { EntityItem } from './types';
import type Schema from 'async-validator';
import type { ValidateFieldsError } from 'async-validator';
import { dialogStyle } from 'CustomTheme';
import { BlockFormControlLabel, ValidatedTextField } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import { numberValue, updateValue } from 'utils';
import { validate } from 'validators';
type SettingsCustomEntitiesDialogProps = {
open: boolean;
creating: boolean;
onClose: () => void;
onSave: (ei: EntityItem) => void;
selectedItem: EntityItem;
validator: Schema;
};
const SettingsCustomEntitiesDialog = ({
open,
creating,
onClose,
onSave,
selectedItem,
validator
}: SettingsCustomEntitiesDialogProps) => {
const { LL } = useI18nContext();
const [editItem, setEditItem] = useState<EntityItem>(selectedItem);
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
const updateFormValue = updateValue(setEditItem);
useEffect(() => {
if (open) {
setFieldErrors(undefined);
setEditItem(selectedItem);
// convert to hex strings straight away
setEditItem({
...selectedItem,
device_id: selectedItem.device_id.toString(16).toUpperCase(),
type_id: selectedItem.type_id.toString(16).toUpperCase()
});
}
}, [open, selectedItem]);
const close = () => {
onClose();
};
const save = async () => {
try {
setFieldErrors(undefined);
await validate(validator, editItem);
if (typeof editItem.device_id === 'string') {
editItem.device_id = parseInt(editItem.device_id, 16);
}
if (typeof editItem.type_id === 'string') {
editItem.type_id = parseInt(editItem.type_id, 16);
}
onSave(editItem);
} catch (errors: any) {
setFieldErrors(errors);
}
};
const remove = () => {
editItem.deleted = true;
onSave(editItem);
};
return (
<Dialog sx={dialogStyle} open={open} onClose={close}>
<DialogTitle>
{creating ? LL.ADD(1) + ' ' + LL.NEW(1) : LL.EDIT()}&nbsp;{LL.ENTITY()}
</DialogTitle>
<DialogContent dividers>
<Box display="flex" flexWrap="wrap" mb={1}>
<Box flexWrap="nowrap" whiteSpace="nowrap" />
</Box>
<Grid container spacing={2}>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="name"
label={LL.NAME(0)}
value={editItem.name}
margin="normal"
fullWidth
onChange={updateFormValue}
/>
</Grid>
<Grid item xs={4}>
<TextField
name="ram"
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
value={editItem.ram}
variant="outlined"
onChange={updateFormValue}
margin="normal"
fullWidth
select
>
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
</TextField>
</Grid>
{editItem.ram === 1 && (
<Grid item xs={4}>
<TextField
name="value"
label={LL.DEFAULT(0) + ' ' + LL.VALUE(1)}
value={editItem.value}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
/>
</Grid>
)}
{editItem.ram === 0 && (
<>
<Grid item xs={4} mt={3}>
<BlockFormControlLabel
control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />}
label={LL.WRITEABLE()}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="device_id"
label={LL.ID_OF(LL.DEVICE())}
margin="normal"
type="string"
fullWidth
value={editItem.device_id as string}
onChange={updateFormValue}
inputProps={{ style: { textTransform: 'uppercase' } }}
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="type_id"
label={LL.ID_OF(LL.TYPE(1))}
margin="normal"
fullWidth
value={editItem.type_id}
onChange={updateFormValue}
inputProps={{ style: { textTransform: 'uppercase' } }}
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="offset"
label={LL.OFFSET()}
margin="normal"
fullWidth
type="number"
value={editItem.offset}
onChange={updateFormValue}
/>
</Grid>
<Grid item xs={4}>
<TextField
name="value_type"
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
value={editItem.value_type}
variant="outlined"
onChange={updateFormValue}
margin="normal"
fullWidth
select
>
<MenuItem value={DeviceValueType.BOOL}>BOOL</MenuItem>
<MenuItem value={DeviceValueType.INT}>INT</MenuItem>
<MenuItem value={DeviceValueType.UINT}>UINT</MenuItem>
<MenuItem value={DeviceValueType.SHORT}>SHORT</MenuItem>
<MenuItem value={DeviceValueType.USHORT}>USHORT</MenuItem>
<MenuItem value={DeviceValueType.ULONG}>ULONG</MenuItem>
<MenuItem value={DeviceValueType.TIME}>TIME</MenuItem>
<MenuItem value={DeviceValueType.STRING}>RAW</MenuItem>
</TextField>
</Grid>
{editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
<>
<Grid item xs={4}>
<TextField
name="factor"
label={LL.FACTOR()}
value={numberValue(editItem.factor)}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
type="number"
inputProps={{ step: '0.001' }}
/>
</Grid>
<Grid item xs={4}>
<TextField
name="uom"
label={LL.UNIT()}
value={editItem.uom}
margin="normal"
fullWidth
onChange={updateFormValue}
select
>
{DeviceValueUOM_s.map((val, i) => (
<MenuItem key={i} value={i}>
{val}
</MenuItem>
))}
</TextField>
</Grid>
</>
)}
{editItem.value_type === DeviceValueType.STRING && editItem.device_id !== '0' && (
<Grid item xs={4}>
<TextField
name="factor"
label="Bytes"
value={editItem.factor}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
type="number"
inputProps={{ min: '1', max: '27', step: '1' }}
/>
</Grid>
)}
</>
)}
</Grid>
</DialogContent>
<DialogActions>
{!creating && (
<Box flexGrow={1}>
<Button startIcon={<RemoveIcon />} variant="outlined" color="warning" onClick={remove}>
{LL.REMOVE()}
</Button>
</Box>
)}
<Button startIcon={<CancelIcon />} variant="outlined" onClick={close} color="secondary">
{LL.CANCEL()}
</Button>
<Button startIcon={creating ? <AddIcon /> : <DoneIcon />} variant="outlined" onClick={save} color="primary">
{creating ? LL.ADD(0) : LL.UPDATE()}
</Button>
</DialogActions>
</Dialog>
);
};
export default SettingsCustomEntitiesDialog;

View File

@@ -514,7 +514,7 @@ const SettingsCustomization: FC = () => {
{devices && renderDeviceList()} {devices && renderDeviceList()}
{deviceEntities && renderDeviceData()} {deviceEntities && renderDeviceData()}
{restartNeeded && ( {restartNeeded && (
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}> <MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}> <Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
{LL.RESTART()} {LL.RESTART()}
</Button> </Button>

View File

@@ -70,7 +70,7 @@ const SettingsCustomizationDialog = ({ open, onClose, onSave, selectedItem }: Se
<DialogContent dividers> <DialogContent dividers>
<Grid container direction="row"> <Grid container direction="row">
<Typography variant="body2" color="warning.main"> <Typography variant="body2" color="warning.main">
{LL.ENTITY() + ' ID'}:&nbsp; {LL.ID_OF(LL.ENTITY())}:&nbsp;
</Typography> </Typography>
<Typography variant="body2">{editItem.id}</Typography> <Typography variant="body2">{editItem.id}</Typography>
</Grid> </Grid>

View File

@@ -1,252 +0,0 @@
import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import {
Box,
Button,
Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
InputAdornment,
MenuItem,
TextField
} from '@mui/material';
import { useEffect, useState } from 'react';
import { DeviceValueUOM_s, DeviceValueType } from './types';
import type { EntityItem } from './types';
import type Schema from 'async-validator';
import type { ValidateFieldsError } from 'async-validator';
import { dialogStyle } from 'CustomTheme';
import { BlockFormControlLabel, ValidatedTextField } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import { updateValue } from 'utils';
import { validate } from 'validators';
type SettingsEntitiesDialogProps = {
open: boolean;
creating: boolean;
onClose: () => void;
onSave: (ei: EntityItem) => void;
selectedItem: EntityItem;
validator: Schema;
};
const SettingsEntitiesDialog = ({
open,
creating,
onClose,
onSave,
selectedItem,
validator
}: SettingsEntitiesDialogProps) => {
const { LL } = useI18nContext();
const [editItem, setEditItem] = useState<EntityItem>(selectedItem);
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
const updateFormValue = updateValue(setEditItem);
useEffect(() => {
if (open) {
setFieldErrors(undefined);
setEditItem(selectedItem);
// convert to hex strings straight away
setEditItem({
...selectedItem,
device_id: selectedItem.device_id.toString(16).toUpperCase(),
type_id: selectedItem.type_id.toString(16).toUpperCase()
});
}
}, [open, selectedItem]);
const close = () => {
onClose();
};
const save = async () => {
try {
setFieldErrors(undefined);
await validate(validator, editItem);
if (typeof editItem.device_id === 'string') {
editItem.device_id = parseInt(editItem.device_id, 16);
}
if (typeof editItem.type_id === 'string') {
editItem.type_id = parseInt(editItem.type_id, 16);
}
onSave(editItem);
} catch (errors: any) {
setFieldErrors(errors);
}
};
const remove = () => {
editItem.deleted = true;
onSave(editItem);
};
return (
<Dialog sx={dialogStyle} open={open} onClose={close}>
<DialogTitle>
{creating ? LL.ADD(1) + ' ' + LL.NEW(1) : LL.EDIT()}&nbsp;{LL.ENTITY()}
</DialogTitle>
<DialogContent dividers>
<Box display="flex" flexWrap="wrap" mb={1}>
<Box flexWrap="nowrap" whiteSpace="nowrap" />
</Box>
<Grid container spacing={2}>
<Grid item xs={8}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="name"
label={LL.NAME(0)}
value={editItem.name}
margin="normal"
fullWidth
onChange={updateFormValue}
/>
</Grid>
<Grid item xs={4} mt={3}>
<BlockFormControlLabel
control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />}
label={LL.WRITEABLE()}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="device_id"
label={LL.ID_OF(LL.DEVICE())}
margin="normal"
type="string"
fullWidth
value={editItem.device_id as string}
onChange={updateFormValue}
inputProps={{ style: { textTransform: 'uppercase' } }}
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="type_id"
label={LL.ID_OF(LL.TYPE(1))}
margin="normal"
fullWidth
value={editItem.type_id}
onChange={updateFormValue}
inputProps={{ style: { textTransform: 'uppercase' } }}
InputProps={{ startAdornment: <InputAdornment position="start">0x</InputAdornment> }}
/>
</Grid>
<Grid item xs={4}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="offset"
label={LL.OFFSET()}
margin="normal"
fullWidth
type="number"
value={editItem.offset}
onChange={updateFormValue}
/>
</Grid>
<Grid item xs={4}>
<TextField
name="value_type"
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
value={editItem.value_type}
variant="outlined"
onChange={updateFormValue}
margin="normal"
fullWidth
select
>
<MenuItem value={DeviceValueType.BOOL}>BOOL</MenuItem>
<MenuItem value={DeviceValueType.INT}>INT</MenuItem>
<MenuItem value={DeviceValueType.UINT}>UINT</MenuItem>
<MenuItem value={DeviceValueType.SHORT}>SHORT</MenuItem>
<MenuItem value={DeviceValueType.USHORT}>USHORT</MenuItem>
<MenuItem value={DeviceValueType.ULONG}>ULONG</MenuItem>
<MenuItem value={DeviceValueType.TIME}>TIME</MenuItem>
<MenuItem value={DeviceValueType.STRING}>RAW</MenuItem>
</TextField>
</Grid>
{editItem.value_type !== DeviceValueType.BOOL && editItem.value_type !== DeviceValueType.STRING && (
<>
<Grid item xs={4}>
<TextField
name="factor"
label={LL.FACTOR()}
value={editItem.factor}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
type="number"
inputProps={{ step: '0.001' }}
/>
</Grid>
<Grid item xs={4}>
<TextField
name="uom"
label={LL.UNIT()}
value={editItem.uom}
margin="normal"
fullWidth
onChange={updateFormValue}
select
>
{DeviceValueUOM_s.map((val, i) => (
<MenuItem key={i} value={i}>
{val}
</MenuItem>
))}
</TextField>
</Grid>
</>
)}
{editItem.value_type === DeviceValueType.STRING && (
<Grid item xs={4}>
<TextField
name="factor"
label="Bytes"
value={editItem.factor}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
type="number"
inputProps={{ min: '1', max: '27', step: '1' }}
/>
</Grid>
)}
</Grid>
</DialogContent>
<DialogActions>
{!creating && (
<Box flexGrow={1}>
<Button startIcon={<RemoveIcon />} variant="outlined" color="warning" onClick={remove}>
{LL.REMOVE()}
</Button>
</Box>
)}
<Button startIcon={<CancelIcon />} variant="outlined" onClick={close} color="secondary">
{LL.CANCEL()}
</Button>
<Button startIcon={creating ? <AddIcon /> : <DoneIcon />} variant="outlined" onClick={save} color="primary">
{creating ? LL.ADD(0) : LL.UPDATE()}
</Button>
</DialogActions>
</Dialog>
);
};
export default SettingsEntitiesDialog;

View File

@@ -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(0)}</HeaderCell> <HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
<HeaderCell stiff>{LL.NAME(0)}</HeaderCell> <HeaderCell stiff>{LL.NAME(0)}</HeaderCell>
</HeaderRow> </HeaderRow>
</Header> </Header>

View File

@@ -19,7 +19,8 @@ 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', {
params: { id }, // alovaInstance.Get<DeviceData>(`/rest/deviceData/${id}`, {
params: { id }, // TODO replace later with id
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);
@@ -53,8 +54,9 @@ export const getSchedule = () => alovaInstance.Get('/rest/getSchedule');
// SettingsCustomization // SettingsCustomization
export const readDeviceEntities = (id: number) => export const readDeviceEntities = (id: number) =>
alovaInstance.Get<DeviceEntity[]>('/rest/deviceEntities', { // alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities/${id}`, {
params: { id }, alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
params: { id }, // TODO replace later with id
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 }));
@@ -86,7 +88,7 @@ export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule',
// SettingsEntities // SettingsEntities
export const readCustomEntities = () => export const readCustomEntities = () =>
alovaInstance.Get<EntityItem[]>('/rest/customentities', { alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
name: 'entities', name: 'entities',
transformData(data: any) { transformData(data: any) {
return data.entities.map((ei: EntityItem) => ({ return data.entities.map((ei: EntityItem) => ({
@@ -104,4 +106,4 @@ export const readCustomEntities = () =>
})); }));
} }
}); });
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customentities', data); export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);

View File

@@ -130,7 +130,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?: number; // steps for up/down, optional s?: string; // steps for up/down, optional
m?: number; // min, optional m?: number; // min, optional
x?: number; // max, optional x?: number; // max, optional
} }
@@ -177,7 +177,8 @@ export enum DeviceValueUOM {
L, L,
KMIN, KMIN,
K, K,
VOLTS VOLTS,
MBAR
} }
export const DeviceValueUOM_s = [ export const DeviceValueUOM_s = [
@@ -204,7 +205,8 @@ export const DeviceValueUOM_s = [
'l', 'l',
'K*min', 'K*min',
'K', 'K',
'V' 'V',
'mbar'
]; ];
export enum AnalogType { export enum AnalogType {
@@ -223,12 +225,12 @@ export enum AnalogType {
export const AnalogTypeNames = [ export const AnalogTypeNames = [
'(disabled)', '(disabled)',
'Digital in', 'Digital In',
'Counter', 'Counter',
'ADC', 'ADC',
'Timer', 'Timer',
'Rate', 'Rate',
'Digital out', 'Digital Out',
'PWM 0', 'PWM 0',
'PWM 1', 'PWM 1',
'PWM 2' 'PWM 2'
@@ -323,6 +325,7 @@ export enum ScheduleFlag {
export interface EntityItem { export interface EntityItem {
id: number; // unique number id: number; // unique number
ram: number;
name: string; name: string;
device_id: number | string; device_id: number | string;
type_id: number | string; type_id: number | string;
@@ -334,6 +337,7 @@ export interface EntityItem {
writeable: boolean; writeable: boolean;
deleted?: boolean; deleted?: boolean;
o_id?: number; o_id?: number;
o_ram?: number;
o_name?: string; o_name?: string;
o_device_id?: number | string; o_device_id?: number | string;
o_type_id?: number | string; o_type_id?: number | string;
@@ -343,6 +347,7 @@ export interface EntityItem {
o_value_type?: number; o_value_type?: number;
o_deleted?: boolean; o_deleted?: boolean;
o_writeable?: boolean; o_writeable?: boolean;
o_value?: any;
} }
export interface Entities { export interface Entities {
@@ -387,6 +392,7 @@ export const enum DeviceValueType {
} }
export const DeviceValueTypeNames = [ export const DeviceValueTypeNames = [
//
'BOOL', 'BOOL',
'INT', 'INT',
'UINT', 'UINT',
@@ -395,6 +401,6 @@ export const DeviceValueTypeNames = [
'ULONG', 'ULONG',
'TIME', 'TIME',
'ENUM', 'ENUM',
'STRING', 'RAW',
'CMD' 'CMD'
]; ];

View File

@@ -1,5 +1,4 @@
export * from './ap'; export * from './ap';
export * from './features';
export * from './me'; export * from './me';
export * from './mqtt'; export * from './mqtt';
export * from './ntp'; export * from './ntp';

View File

@@ -25,6 +25,7 @@ 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;

View File

@@ -33,6 +33,7 @@ export interface NetworkStatus {
gateway_ip: string; gateway_ip: string;
dns_ip_1: string; dns_ip_1: string;
dns_ip_2: string; dns_ip_2: string;
hostname: string;
} }
export interface NetworkSettings { export interface NetworkSettings {
@@ -41,7 +42,7 @@ export interface NetworkSettings {
password: string; password: string;
hostname: string; hostname: string;
static_ip_config: boolean; static_ip_config: boolean;
enableIPv6: boolean; enableIPv6?: boolean;
bandwidth20: boolean; bandwidth20: boolean;
nosleep: boolean; nosleep: boolean;
tx_power: number; tx_power: number;

View File

@@ -9,7 +9,6 @@ export interface NTPStatus {
utc_time: string; utc_time: string;
local_time: string; local_time: string;
server: string; server: string;
uptime: number;
} }
export interface NTPSettings { export interface NTPSettings {

View File

@@ -2,9 +2,14 @@ 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;

View File

@@ -33,7 +33,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions2<D>) => {
}; };
onWriteSuccess(() => { onWriteSuccess(() => {
toast.success(LL.UPDATED_OF(LL.SETTINGS())); toast.success(LL.UPDATED_OF(LL.SETTINGS(0)));
setDirtyFlags([]); setDirtyFlags([]);
}); });

View File

@@ -1,91 +0,0 @@
import { debounce } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react';
import Sockette from 'sockette';
import { addAccessTokenParameter } from 'api/authentication';
interface WebSocketIdMessage {
type: 'id';
id: string;
}
interface WebSocketPayloadMessage<D> {
type: 'payload';
origin_id: string;
payload: D;
}
export type WebSocketMessage<D> = WebSocketIdMessage | WebSocketPayloadMessage<D>;
export const useWs = <D>(wsUrl: string, wsThrottle = 100) => {
const ws = useRef<Sockette>();
const clientId = useRef<string>();
const [connected, setConnected] = useState<boolean>(false);
const [data, setData] = useState<D>();
const [transmit, setTransmit] = useState<boolean>();
const [clear, setClear] = useState<boolean>();
const onMessage = useCallback((event: MessageEvent) => {
const rawData = event.data;
if (typeof rawData === 'string' || rawData instanceof String) {
const message = JSON.parse(rawData as string) as WebSocketMessage<D>;
switch (message.type) {
case 'id':
clientId.current = message.id;
break;
case 'payload':
if (clientId.current) {
setData((existingData) => (clientId.current === message.origin_id && existingData) || message.payload);
}
break;
}
}
}, []);
const doSaveData = useCallback((newData: D, clearData = false) => {
if (!ws.current) {
return;
}
if (clearData) {
setData(undefined);
}
ws.current.json(newData);
}, []);
const saveData = useRef(debounce(doSaveData, wsThrottle));
const updateData = (newData: React.SetStateAction<D | undefined>, transmitData: true, clearData: false) => {
setData(newData);
setTransmit(transmitData);
setClear(clearData);
};
useEffect(() => {
if (!transmit) {
return;
}
data && saveData.current(data, clear);
setTransmit(false);
setClear(false);
}, [doSaveData, data, transmit, clear]);
useEffect(() => {
const instance = new Sockette(addAccessTokenParameter(wsUrl), {
onmessage: onMessage,
onopen: () => {
setConnected(true);
},
onclose: () => {
clientId.current = undefined;
setConnected(false);
setData(undefined);
}
});
ws.current = instance;
// eslint-disable-next-line @typescript-eslint/unbound-method
return instance.close;
}, [wsUrl, onMessage]);
return { connected, data, updateData } as const;
};

View File

@@ -14,9 +14,5 @@ export const createNetworkSettingsValidator = (networkSettings: NetworkSettings)
subnet_mask: [{ required: true, message: 'Subnet mask is required' }, IP_ADDRESS_VALIDATOR], subnet_mask: [{ required: true, message: 'Subnet mask is required' }, IP_ADDRESS_VALIDATOR],
dns_ip_1: IP_ADDRESS_VALIDATOR, dns_ip_1: IP_ADDRESS_VALIDATOR,
dns_ip_2: IP_ADDRESS_VALIDATOR dns_ip_2: IP_ADDRESS_VALIDATOR
}), })
tx_power: [
{ required: true, message: 'Tx Power is required' },
{ type: 'number', min: 0, max: 20, message: 'Tx Power must be between 0 and 20dBm' }
]
}); });

View File

@@ -33,7 +33,7 @@ export const IP_ADDRESS_VALIDATOR = {
} }
}; };
const HOSTNAME_LENGTH_REGEXP = /^.{0,63}$/; const HOSTNAME_LENGTH_REGEXP = /^.{0,200}$/;
const HOSTNAME_PATTERN_REGEXP = const HOSTNAME_PATTERN_REGEXP =
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/; /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/;
@@ -42,7 +42,7 @@ const isValidHostname = (value: string) => HOSTNAME_LENGTH_REGEXP.test(value) &&
export const HOSTNAME_VALIDATOR = { export const HOSTNAME_VALIDATOR = {
validator(rule: InternalRuleItem, value: string, callback: (error?: string) => void) { validator(rule: InternalRuleItem, value: string, callback: (error?: string) => void) {
if (value && !isValidHostname(value)) { if (value && !isValidHostname(value)) {
callback('Must be a valid hostname of up to 63 characters'); callback('Must be a valid hostname');
} else { } else {
callback(); callback();
} }
@@ -52,7 +52,7 @@ export const HOSTNAME_VALIDATOR = {
export const IP_OR_HOSTNAME_VALIDATOR = { export const IP_OR_HOSTNAME_VALIDATOR = {
validator(rule: InternalRuleItem, value: string, callback: (error?: string) => void) { validator(rule: InternalRuleItem, value: string, callback: (error?: string) => void) {
if (value && !(isValidIpAddress(value) || isValidHostname(value))) { if (value && !(isValidIpAddress(value) || isValidHostname(value))) {
callback('Must be a valid IP address or hostname of up to 63 characters'); callback('Must be a valid IP address or hostname');
} else { } else {
callback(); callback();
} }

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'vite'; import { defineConfig, splitVendorChunkPlugin } from 'vite';
import viteTsconfigPaths from 'vite-tsconfig-paths'; import viteTsconfigPaths from 'vite-tsconfig-paths';
import preact from '@preact/preset-vite'; import preact from '@preact/preset-vite';
import viteImagemin from 'vite-plugin-imagemin'; import viteImagemin from 'vite-plugin-imagemin';
@@ -44,6 +44,7 @@ export default defineConfig(({ command, mode }) => {
plugins: [ plugins: [
preact(), preact(),
viteTsconfigPaths(), viteTsconfigPaths(),
splitVendorChunkPlugin(),
{ {
...viteImagemin({ ...viteImagemin({
verbose: false, verbose: false,
@@ -112,6 +113,20 @@ export default defineConfig(({ command, mode }) => {
nameCache: null, nameCache: null,
safari10: false, safari10: false,
toplevel: 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';
}
}
}
} }
} }
}; };

File diff suppressed because it is too large Load Diff

2
lib/ArduinoJson/ArduinoJson.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#include "src/ArduinoJson.h" #include "src/ArduinoJson.h"

922
lib/ArduinoJson/CHANGELOG.md Normal file → Executable file
View File

@@ -1,854 +1,130 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
v6.21.3 (2023-07-23) v7.0.3 (2024-02-05)
------- ------
* Fix compatibility with the Blynk libary (issue #1914) * Improve error messages when using `char` or `char*` (issue #2043)
* Reduce stack consumption (issue #2046)
* Fix compatibility with GCC 4.8 (issue #2045)
v7.0.2 (2024-01-19)
------
* Fix assertion `poolIndex < count_` after `JsonDocument::clear()` (issue #2034)
v7.0.1 (2024-01-10)
------
* Fix "no matching function" with `JsonObjectConst::operator[]` (issue #2019)
* Remove unused files in the PlatformIO package
* Fix `volatile bool` serialized as `1` or `0` instead of `true` or `false` (issue #2029)
v7.0.0 (2024-01-03)
------
* Remove `BasicJsonDocument`
* Remove `StaticJsonDocument`
* Add abstract `Allocator` class
* Merge `DynamicJsonDocument` with `JsonDocument`
* Remove `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()`
* Remove `ARDUINOJSON_ENABLE_STRING_DEDUPLICATION` (string deduplication cannot be disabled anymore)
* Remove `JsonDocument::capacity()`
* Store the strings in the heap
* Reference-count shared strings
* Always store `serialized("string")` by copy (#1915)
* Remove the zero-copy mode of `deserializeJson()` and `deserializeMsgPack()`
* Fix double lookup in `to<JsonVariant>()` * Fix double lookup in `to<JsonVariant>()`
* Fix double call to `size()` in `serializeMsgPack()` * Fix double call to `size()` in `serializeMsgPack()`
* Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name * Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name
* Remove `JsonVariant::shallowCopy()`
* `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
* `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
* Show a link to the documentation when user passes an unsupported input type * Show a link to the documentation when user passes an unsupported input type
* Remove `JsonDocument::memoryUsage()`
v6.21.2 (2023-04-12) * Remove `JsonDocument::garbageCollect()`
------- * Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
* Call `shrinkToFit()` in `deserializeJson()` and `deserializeMsgPack()`
* Fix compatibility with the Zephyr Project (issue #1905) * `serializeJson()` and `serializeMsgPack()` replace the content of `std::string` and `String` instead of appending to it
* Allow using PROGMEM outside of Arduino (issue #1903) * Replace `add()` with `add<T>()` (`add(T)` is still supported)
* Set default for `ARDUINOJSON_ENABLE_PROGMEM` to `1` on AVR * Remove `createNestedArray()` and `createNestedObject()` (use `to<JsonArray>()` and `to<JsonObject>()` instead)
v6.21.1 (2023-03-27)
-------
* Double speed of `DynamicJsonDocument::garbageCollect()`
* Fix compatibility with GCC 5.2 (issue #1897)
v6.21.0 (2023-03-14)
-------
* Drop support for C++98/C++03. Minimum required is C++11.
* Remove `ARDUINOJSON_NAMESPACE`; use `ArduinoJson` instead.
* Make string support generic (issue #1807)
v6.20.1 (2023-02-08)
-------
* Remove explicit exclusion of `as<char*>()` and `as<char>()` (issue #1860)
If you try to call them, you'll now get the same error message as any unsupported type.
You could also add a custom converter for `char*` and `char`.
v6.20.0 (2022-12-26)
-------
* Add `JsonVariant::shallowCopy()` (issue #1343)
* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
* Fix lax parsing of `true`, `false`, and `null` (issue #1781)
* Remove undocumented `accept()` functions
* Rename `addElement()` to `add()`
* Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()`
* Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()`
* Remove undocumented `JsonArrayIterator::internal()` and `JsonObjectIterator::internal()`
* Rename things in `ARDUINOJSON_NAMESPACE` to match the public names
* Add documentation to most public symbols
* Remove support for naked `char` (was deprecated since 6.18.0)
> ### BREAKING CHANGES > ### BREAKING CHANGES
> >
> This release hides `JsonVariant`'s functions that were only intended for internal use. > As every major release, ArduinoJson 7 introduces several breaking changes.
> If you were using them in your programs, you must replace with `operator[]` and `to<JsonVariant>()`, like so: > I added some stubs so that most existing programs should compile, but I highty recommend you upgrade your code.
>
> #### `JsonDocument`
>
> In ArduinoJson 6, you could allocate the memory pool on the stack (with `StaticJsonDocument`) or in the heap (with `DynamicJsonDocument`).
> In ArduinoJson 7, the memory pool is always allocated in the heap, so `StaticJsonDocument` and `DynamicJsonDocument` have been merged into `JsonDocument`.
>
> In ArduinoJson 6, `JsonDocument` had a fixed capacity; in ArduinoJson 7, it has an elastic capacity that grows as needed.
> Therefore, you don't need to specify the capacity anymore, so the macros `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()` have been removed.
> >
> ```c++ > ```c++
> // before > // ArduinoJson 6
> JsonVariant a = variant.getElement(idx); > StaticJsonDocument<256> doc;
> JsonVariant b = variant.getOrAddElement(idx); > // or
> JsonVariant c = variant.getMember(key); > DynamicJsonDocument doc(256);
> JsonVariant d = variant.getOrAddMember(key);
> >
> // after > // ArduinoJson 7
> JsonVariant a = variant[idx]; > JsonDocument doc;
> JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>();
> JsonVariant c = variant[key];
> JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
> ```
v6.19.4 (2022-04-05)
-------
* Add `ElementProxy::memoryUsage()`
* Add `MemberProxy::memoryUsage()` (issue #1730)
* Add implicit conversion from `JsonDocument` to `JsonVariant`
* Fix comparisons operators with `const JsonDocument&`
v6.19.3 (2022-03-08)
-------
* Fix `call of overloaded 'String(const char*, int)' is ambiguous`
* Fix `JsonString` operator `==` and `!=` for non-zero-terminated string
* Fix `-Wsign-conversion` on GCC 8 (issue #1715)
* MessagePack: serialize round floats as integers (issue #1718)
v6.19.2 (2022-02-14)
-------
* Fix `cannot convert 'pgm_p' to 'const void*'` (issue #1707)
v6.19.1 (2022-01-14)
-------
* Fix crash when adding an object member in a too small `JsonDocument`
* Fix filter not working in zero-copy mode (issue #1697)
v6.19.0 (2022-01-08)
-------
* Remove `ARDUINOJSON_EMBEDDED_MODE` and assume we run on an embedded platform.
Dependent settings (like `ARDUINOJSON_DEFAULT_NESTING_LIMIT`) must be set individually.
* Change the default of `ARDUINOJSON_USE_DOUBLE` to `1`
* Change the default of `ARDUINOJSON_USE_LONG_LONG` to `1` on 32-bit platforms
* Add `as<JsonString>()` and `is<JsonString>()`
* Add safe bool idiom in `JsonString`
* Add support for NUL in string values (issue #1646)
* Add support for arbitrary array rank in `copyArray()`
* Add support for `char[][]` in `copyArray()`
* Remove `DeserializationError == bool` and `DeserializationError != bool`
* Renamed undocumented function `isUndefined()` to `isUnbound()`
* Fix `JsonVariant::memoryUsage()` for raw strings
* Fix `call of overloaded 'swap(BasicJsonDocument&, BasicJsonDocument&)' is ambiguous` (issue #1678)
* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move constructors
* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move assignments
* Fix return type of `StaticJsonDocument::operator=`
* Avoid pool reallocation in `BasicJsonDocument`'s copy assignment if capacity is the same
* Avoid including `Arduino.h` when all its features are disabled (issue #1692, PR #1693 by @paulocsanz)
* Assume `PROGMEM` is available as soon as `ARDUINO` is defined (consequence of #1693)
v6.18.5 (2021-09-28)
-------
* Set `ARDUINOJSON_EMBEDDED_MODE` to `1` on Nios II (issue #1657)
v6.18.4 (2021-09-06)
-------
* Fixed error `'dummy' may be used uninitialized` on GCC 11
* Fixed error `expected unqualified-id before 'const'` on GCC 11 (issue #1622)
* Filter: exact match takes precedence over wildcard (issue #1628)
* Fixed deserialization of `\u0000` (issue #1646)
v6.18.3 (2021-07-27)
-------
* Changed return type of `convertToJson()` and `Converter<T>::toJson()` to `void`
* Added `as<std::string_view>()` and `is<std::string_view>()`
v6.18.2 (2021-07-19)
-------
* Removed a symlink because the Arduino Library Specification forbids it
v6.18.1 (2021-07-03)
-------
* Fixed support for `volatile float` and `volatile double` (issue #1557)
* Fixed error `[Pe070]: incomplete type is not allowed` on IAR (issue #1560)
* Fixed `serializeJson(doc, String)` when allocation fails (issue #1572)
* Fixed clang-tidy warnings (issue #1574, PR #1577 by @armandas)
* Added fake class `InvalidConversion<T1,T2>` to easily identify invalid conversions (issue #1585)
* Added support for `std::string_view` (issue #1578, PR #1554 by @0xFEEDC0DE64)
* Fixed warning `definition of implicit copy constructor for 'MsgPackDeserializer' is deprecated because it has a user-declared copy assignment operator`
* Added `JsonArray::clear()` (issue #1597)
* Fixed `JsonVariant::as<unsigned>()` (issue #1601)
* Added support for ESP-IDF component build (PR #1562 by @qt1, PR #1599 by @andreaskuster)
v6.18.0 (2021-05-05)
-------
* Added support for custom converters (issue #687)
* Added support for `Printable` (issue #1444)
* Removed support for `char` values, see below (issue #1498)
* `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported`
* `deserializeMsgPack()` inserts `null` instead of returning `NotSupported`
* Removed `DeserializationError::NotSupported`
* Added `JsonVariant::is<JsonArrayConst/JsonObjectConst>()` (issue #1412)
* Added `JsonVariant::is<JsonVariant/JsonVariantConst>()` (issue #1412)
* Changed `JsonVariantConst::is<JsonArray/JsonObject>()` to return `false` (issue #1412)
* Simplified `JsonVariant::as<T>()` to always return `T` (see below)
* Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
* Fixed member-call-on-null-pointer in `getMember()` when array is empty
* `serializeMsgPack(doc, buffer, size)` doesn't add null-terminator anymore (issue #1545)
* `serializeJson(doc, buffer, size)` adds null-terminator only if there is enough room
* PlatformIO: set `build.libArchive` to `false` (PR #1550 by @askreet)
> ### BREAKING CHANGES
>
> #### Support for `char` removed
>
> We cannot cast a `JsonVariant` to a `char` anymore, so the following will break:
> ```c++
> char age = doc["age"]; // error: no matching function for call to 'variantAs(VariantData*&)'
> ```
> Instead, you must use another integral type, such as `int8_t`:
> ```c++
> int8_t age = doc["age"]; // OK
> ``` > ```
> >
> Similarly, we cannot assign from a `char` anymore, so the following will break: > In ArduinoJson 7, `JsonDocument` reuses released memory, so `garbageCollect()` has been removed.
> ```c++ > `shrinkToFit()` is still available and releases the over-allocated memory.
> char age;
> doc["age"] = age; // error: no matching function for call to 'VariantRef::set(const char&)'
> ```
> Instead, you must use another integral type, such as `int8_t`:
> ```c++
> int8_t age;
> doc["age"] = age; // OK
> ```
> A deprecation warning with the message "Support for `char` is deprecated, use `int8_t` or `uint8_t` instead" was added to allow a smooth transition.
> >
> #### `as<T>()` always returns `T` > Due to a change in the implementation, it's not possible to store a pointer to a variant from another `JsonDocument`, so `shallowCopy()` has been removed.
> >
> Previously, `JsonVariant::as<T>()` could return a type different from `T`. > In ArduinoJson 6, the meaning of `memoryUsage()` was clear: it returned the number of bytes used in the memory pool.
> The most common example is `as<char*>()` that returned a `const char*`. > In ArduinoJson 7, the meaning of `memoryUsage()` would be ambiguous, so it has been removed.
> While this feature simplified a few use cases, it was confusing and complicated the
> implementation of custom converters.
> >
> Starting from this version, `as<T>` doesn't try to auto-correct the return type and always return `T`, > #### Custom allocators
> which means that you cannot write this anymore: >
> In ArduinoJson 6, you could specify a custom allocator class as a template parameter of `BasicJsonDocument`.
> In ArduinoJson 7, you must inherit from `ArduinoJson::Allocator` and pass a pointer to an instance of your class to the constructor of `JsonDocument`.
> >
> ```c++ > ```c++
> Serial.println(doc["sensor"].as<char*>()); // error: invalid conversion from 'const char*' to 'char*' [-fpermissive] > // ArduinoJson 6
> class MyAllocator {
> // ...
> };
> BasicJsonDocument<MyAllocator> doc(256);
>
> // ArduinoJson 7
> class MyAllocator : public ArduinoJson::Allocator {
> // ...
> };
> MyAllocator myAllocator;
> JsonDocument doc(&myAllocator);
> ``` > ```
> >
> Instead, you must write: > #### `createNestedArray()` and `createNestedObject()`
>
> In ArduinoJson 6, you could create a nested array or object with `createNestedArray()` and `createNestedObject()`.
> In ArduinoJson 7, you must use `add<T>()` or `to<T>()` instead.
>
> For example, to create `[[],{}]`, you would write:
> >
> ```c++ > ```c++
> Serial.println(doc["sensor"].as<const char*>()); // OK > // ArduinoJson 6
> arr.createNestedArray();
> arr.createNestedObject();
>
> // ArduinoJson 7
> arr.add<JsonArray>();
> arr.add<JsonObject>();
> ``` > ```
> >
> A deprecation warning with the message "Replace `as<char*>()` with `as<const char*>()`" was added to allow a smooth transition. > And to create `{"array":[],"object":{}}`, you would write:
>
> #### `DeserializationError::NotSupported` removed
>
> On a different topic, `DeserializationError::NotSupported` has been removed.
> Instead of returning this error:
>
> * `deserializeJson()` leaves `\uXXXX` unchanged (only when `ARDUINOJSON_DECODE_UNICODE` is `0`)
> * `deserializeMsgPack()` replaces unsupported values with `null`s
>
> #### Const-aware `is<T>()`
>
> Lastly, a very minor change concerns `JsonVariantConst::is<T>()`.
> It used to return `true` for `JsonArray` and `JsonOject`, but now it returns `false`.
> Instead, you must use `JsonArrayConst` and `JsonObjectConst`.
v6.17.3 (2021-02-15)
-------
* Made `JsonDocument`'s destructor protected (issue #1480)
* Added missing calls to `client.stop()` in `JsonHttpClient.ino` (issue #1485)
* Fixed error `expected ')' before 'char'` when `isdigit()` is a macro (issue #1487)
* Fixed error `definition of implicit copy constructor is deprecated` on Clang 10
* PlatformIO: set framework compatibility to `*` (PR #1490 by @maxgerhardt)
v6.17.2 (2020-11-14)
-------
* Fixed invalid conversion error in `operator|(JsonVariant, char*)` (issue #1432)
* Changed the default value of `ARDUINOJSON_ENABLE_PROGMEM` (issue #1433).
It now checks that the `pgm_read_XXX` macros are defined before enabling `PROGMEM`.
v6.17.1 (2020-11-07)
-------
* Fixed error `ambiguous overload for 'operator|'` (issue #1411)
* Fixed `operator|(MemberProxy, JsonObject)` (issue #1415)
* Allowed more than 32767 values in non-embedded mode (issue #1414)
v6.17.0 (2020-10-19)
-------
* Added a build failure when nullptr is defined as a macro (issue #1355)
* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
* Added `DeserializationError::EmptyInput` which tells if the input was empty
* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
* Added `operator|(JsonVariantConst, JsonVariantConst)`
* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella)
* Moved float convertion tables to PROGMEM
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
v6.16.1 (2020-08-04)
-------
* Fixed `deserializeJson()` that stopped reading after `{}` (issue #1335)
v6.16.0 (2020-08-01)
-------
* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
* Added string deduplication (issue #1303)
* Added `JsonString::operator!=`
* Added wildcard key (`*`) for filters (issue #1309)
* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default
* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy`
* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311)
* Fixed excessive stack usage when compiled with `-Og` (issues #1210 and #1314)
* Fixed `Warning[Pa093]: implicit conversion from floating point to integer` on IAR compiler (PR #1328 by @stawiski)
v6.15.2 (2020-05-15)
-------
* CMake: don't build tests when imported in another project
* CMake: made project arch-independent
* Visual Studio: fixed error C2766 with flag `/Zc:__cplusplus` (issue #1250)
* Added support for `JsonDocument` to `copyArray()` (issue #1255)
* Added support for `enum`s in `as<T>()` and `is<T>()` (issue #1256)
* Added `JsonVariant` as an input type for `deserializeXxx()`
For example, you can do: `deserializeJson(doc2, doc1["payload"])`
* Break the build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0
v6.15.1 (2020-04-08)
-------
* Fixed "maybe-uninitialized" warning (issue #1217)
* Fixed "statement is unreachable" warning on IAR (issue #1233)
* Fixed "pointless integer comparison" warning on IAR (issue #1233)
* Added CMake "install" target (issue #1209)
* Disabled alignment on AVR (issue #1231)
v6.15.0 (2020-03-22)
-------
* Added `DeserializationOption::Filter` (issue #959)
* Added example `JsonFilterExample.ino`
* Changed the array subscript operator to automatically add missing elements
* Fixed "deprecated-copy" warning on GCC 9 (fixes #1184)
* Fixed `MemberProxy::set(char[])` not duplicating the string (issue #1191)
* Fixed enums serialized as booleans (issue #1197)
* Fixed incorrect string comparison on some platforms (issue #1198)
* Added move-constructor and move-assignment to `BasicJsonDocument`
* Added `BasicJsonDocument::garbageCollect()` (issue #1195)
* Added `StaticJsonDocument::garbageCollect()`
* Changed copy-constructor of `BasicJsonDocument` to preserve the capacity of the source.
* Removed copy-constructor of `JsonDocument` (issue #1189)
> ### BREAKING CHANGES
>
> #### Copy-constructor of `BasicJsonDocument`
>
> In previous versions, the copy constructor of `BasicJsonDocument` looked at the source's `memoryUsage()` to choose its capacity.
> Now, the copy constructor of `BasicJsonDocument` uses the same capacity as the source.
>
> Example:
> >
> ```c++ > ```c++
> DynamicJsonDocument doc1(64); > // ArduinoJson 6
> doc1.set(String("example")); > obj.createNestedArray("array");
> obj.createNestedObject("object");
> >
> DynamicJsonDocument doc2 = doc1; > // ArduinoJson 7
> Serial.print(doc2.capacity()); // 8 with ArduinoJson 6.14 > obj["array"].to<JsonArray>();
> // 64 with ArduinoJson 6.15 > obj["object"].to<JsonObject>();
> ```
>
> I made this change to get consistent results between copy-constructor and move-constructor, and whether RVO applies or not.
>
> If you use the copy-constructor to optimize your documents, you can use `garbageCollect()` or `shrinkToFit()` instead.
>
> #### Copy-constructor of `JsonDocument`
>
> In previous versions, it was possible to create a function that take a `JsonDocument` by value.
>
> ```c++
> void myFunction(JsonDocument doc) {}
> ```
>
> This function gives the wrong clues because it doesn't receive a copy of the `JsonDocument`, only a sliced version.
> It worked because the copy constructor copied the internal pointers, but it was an accident.
>
> From now, if you need to pass a `JsonDocument` to a function, you must use a reference:
>
> ```c++
> void myFunction(JsonDocument& doc) {}
> ```
v6.14.1 (2020-01-27)
-------
* Fixed regression in UTF16 decoding (issue #1173)
* Fixed `containsKey()` on `JsonVariantConst`
* Added `getElement()` and `getMember()` to `JsonVariantConst`
v6.14.0 (2020-01-16)
-------
* Added `BasicJsonDocument::shrinkToFit()`
* Added support of `uint8_t` for `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` (issue #1142)
* Added `ARDUINOJSON_ENABLE_COMMENTS` to enable support for comments (defaults to 0)
* Auto enable support for `std::string` and `std::stream` on modern compilers (issue #1156)
(No need to define `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_STD_STREAM` anymore)
* Improved decoding of UTF-16 surrogate pairs (PR #1157 by @kaysievers)
(ArduinoJson now produces standard UTF-8 instead of CESU-8)
* Added `measureJson`, `measureJsonPretty`, and `measureMsgPack` to `keywords.txt`
(This file is used for syntax highlighting in the Arduino IDE)
* Fixed `variant.is<nullptr_t>()`
* Fixed value returned by `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
* Improved speed of `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
> ### BREAKING CHANGES
>
> #### Comments
>
> Support for comments in input is now optional and disabled by default.
>
> If you need support for comments, you must defined `ARDUINOJSON_ENABLE_COMMENTS` to `1`; otherwise, you'll receive `InvalidInput` errors.
>
> ```c++
> #define ARDUINOJSON_ENABLE_COMMENTS 1
> #include <ArduinoJson.h>
> ```
v6.13.0 (2019-11-01)
-------
* Added support for custom writer/reader classes (issue #1088)
* Added conversion from `JsonArray` and `JsonObject` to `bool`, to be consistent with `JsonVariant`
* Fixed `deserializeJson()` when input contains duplicate keys (issue #1095)
* Improved `deserializeMsgPack()` speed by reading several bytes at once
* Added detection of Atmel AVR8/GNU C Compiler (issue #1112)
* Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47)
* Fixed dangling reference in copies of `MemberProxy` and `ElementProxy` (issue #1120)
v6.12.0 (2019-09-05)
-------
* Use absolute instead of relative includes (issue #1072)
* Changed `JsonVariant::as<bool>()` to return `true` for any non-null value (issue #1005)
* Moved ancillary files to `extras/` (issue #1011)
v6.11.5 (2019-08-23)
-------
* Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073)
v6.11.4 (2019-08-12)
-------
* Added `measureJson()` to the `ArduinoJson` namespace (PR #1069 by @nomis)
* Added support for `basic_string<char, traits, allocator>` (issue #1045)
* Fixed example `JsonConfigFile.ino` for ESP8266
* Include `Arduino.h` if `ARDUINO` is defined (PR #1071 by @nomis)
v6.11.3 (2019-07-22)
-------
* Added operators `==` and `!=` for `JsonDocument`, `ElementProxy`, and `MemberProxy`
* Fixed comparison of `JsonVariant` when one contains a linked string and the other contains an owned string (issue #1051)
v6.11.2 (2019-07-08)
-------
* Fixed assignment of `JsonDocument` to `JsonVariant` (issue #1023)
* Fix invalid conversion error on Particle Argon (issue #1035)
v6.11.1 (2019-06-21)
-------
* Fixed `serialized()` not working with Flash strings (issue #1030)
v6.11.0 (2019-05-26)
-------
* Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978)
* Fixed invalid result from `operator|` (issue #981)
* Made `deserializeJson()` more picky about trailing characters (issue #980)
* Added `ARDUINOJSON_ENABLE_NAN` (default=0) to enable NaN in JSON (issue #973)
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
* Removed implicit conversion in comparison operators (issue #998)
* Added lexicographical comparison for `JsonVariant`
* Added support for `nullptr` (issue #998)
> ### BREAKING CHANGES
>
> #### NaN and Infinity
>
> The JSON specification allows neither NaN not Infinity, but previous
> versions of ArduinoJson supported it. Now, ArduinoJson behaves like most
> other libraries: a NaN or and Infinity in the `JsonDocument`, becomes
> a `null` in the output JSON. Also, `deserializeJson()` returns
> `InvalidInput` if the JSON document contains NaN or Infinity.
>
> This version still supports NaN and Infinity in JSON documents, but
> it's disabled by default to be compatible with other JSON parsers.
> If you need the old behavior back, define `ARDUINOJSON_ENABLE_NAN` and
> `ARDUINOJSON_ENABLE_INFINITY` to `1`;:
>
> ```c++
> #define ARDUINOJSON_ENABLE_NAN 1
> #define ARDUINOJSON_ENABLE_INFINITY 1
> #include <ArduinoJson.h>
> ```
>
> #### The "or" operator
>
> This version slightly changes the behavior of the | operator when the
> variant contains a float and the user requests an integer.
>
> Older versions returned the floating point value truncated.
> Now, it returns the default value.
>
> ```c++
> // suppose variant contains 1.2
> int value = variant | 3;
>
> // old behavior:
> value == 1
>
> // new behavior
> value == 3
> ```
>
> If you need the old behavior, you must add `if (variant.is<float>())`.
v6.10.1 (2019-04-23)
-------
* Fixed error "attributes are not allowed on a function-definition"
* Fixed `deserializeJson()` not being picky enough (issue #969)
* Fixed error "no matching function for call to write(uint8_t)" (issue #972)
v6.10.0 (2019-03-22)
-------
* Fixed an integer overflow in the JSON deserializer
* Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
- `as<T>()` returns `0` if the integer `T` overflows
- `is<T>()` returns `false` if the integer `T` overflows
* Added `BasicJsonDocument` to support custom allocator (issue #876)
* Added `JsonDocument::containsKey()` (issue #938)
* Added `JsonVariant::containsKey()`
v6.9.1 (2019-03-01)
------
* Fixed warning "unused variable" with GCC 4.4 (issue #912)
* Fixed warning "cast increases required alignment" (issue #914)
* Fixed warning "conversion may alter value" (issue #914)
* Fixed naming conflict with "CAPACITY" (issue #839)
* Muted warning "will change in GCC 7.1" (issue #914)
* Added a clear error message for `StaticJsonBuffer` and `DynamicJsonBuffer`
* Marked ArduinoJson.h as a "system header"
v6.9.0 (2019-02-26)
------
* Decode escaped Unicode characters like \u00DE (issue #304, PR #791)
Many thanks to Daniel Schulte (aka @trilader) who implemented this feature.
* Added option ARDUINOJSON_DECODE_UNICODE to enable it
* Converted `JsonArray::copyFrom()/copyTo()` to free functions `copyArray()`
* Renamed `JsonArray::copyFrom()` and `JsonObject::copyFrom()` to `set()`
* Renamed `JsonArray::get()` to `getElement()`
* Renamed `JsonArray::add()` (without arg) to `addElement()`
* Renamed `JsonObject::get()` to `getMember()`
* Renamed `JsonObject::getOrCreate()` to `getOrAddMember()`
* Fixed `JsonVariant::isNull()` not returning `true` after `set((char*)0)`
* Fixed segfault after `variant.set(serialized((char*)0))`
* Detect `IncompleteInput` in `false`, `true`, and `null`
* Added `JsonDocument::size()`
* Added `JsonDocument::remove()`
* Added `JsonVariant::clear()`
* Added `JsonVariant::remove()`
v6.8.0-beta (2019-01-30)
-----------
* Import functions in the ArduinoJson namespace to get clearer errors
* Improved syntax highlighting in Arduino IDE
* Removed default capacity of `DynamicJsonDocument`
* `JsonArray::copyFrom()` accepts `JsonArrayConst`
* `JsonVariant::set()` accepts `JsonArrayConst` and `JsonObjectConst`
* `JsonDocument` was missing in the ArduinoJson namespace
* Added `memoryUsage()` to `JsonArray`, `JsonObject`, and `JsonVariant`
* Added `nesting()` to `JsonArray`, `JsonDocument`, `JsonObject`, and `JsonVariant`
* Replaced `JsonDocument::nestingLimit` with an additional parameter
to `deserializeJson()` and `deserializeMsgPack()`
* Fixed uninitialized variant in `JsonDocument`
* Fixed `StaticJsonDocument` copy constructor and copy assignment
* The copy constructor of `DynamicJsonDocument` chooses the capacity according to the memory usage of the source, not from the capacity of the source.
* Added the ability to create/assign a `StaticJsonDocument`/`DynamicJsonDocument` from a `JsonArray`/`JsonObject`/`JsonVariant`
* Added `JsonDocument::isNull()`
* Added `JsonDocument::operator[]`
* Added `ARDUINOJSON_TAB` to configure the indentation character
* Reduced the size of the pretty JSON serializer
* Added `add()`, `createNestedArray()` and `createNestedObject()` to `JsonVariant`
* `JsonVariant` automatically promotes to `JsonObject` or `JsonArray` on write.
Calling `JsonVariant::to<T>()` is not required anymore.
* `JsonDocument` now support the same operations as `JsonVariant`.
Calling `JsonDocument::as<T>()` is not required anymore.
* Fixed example `JsonHttpClient.ino`
* User can now use a `JsonString` as a key or a value
> ### BREAKING CHANGES
>
> #### `DynamicJsonDocument`'s constructor
>
> The parameter to the constructor of `DynamicJsonDocument` is now mandatory
>
> Old code:
>
> ```c++
> DynamicJsonDocument doc;
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc(1024);
> ```
>
> #### Nesting limit
>
> `JsonDocument::nestingLimit` was replaced with a new parameter to `deserializeJson()` and `deserializeMsgPack()`.
>
> Old code:
>
> ```c++
> doc.nestingLimit = 15;
> deserializeJson(doc, input);
> ```
>
> New code:
>
> ```c++
> deserializeJson(doc, input, DeserializationOption::NestingLimit(15));
> ```
v6.7.0-beta (2018-12-07)
-----------
* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
* Restored the monotonic allocator because the code was getting too big
* Reduced the memory usage
* Reduced the code size
* Renamed `JsonKey` to `JsonString`
* Removed spurious files in the Particle library
v6.6.0-beta (2018-11-13)
-----------
* Removed `JsonArray::is<T>(i)` and `JsonArray::set(i,v)`
* Removed `JsonObject::is<T>(k)` and `JsonObject::set(k,v)`
* Replaced `T JsonArray::get<T>(i)` with `JsonVariant JsonArray::get(i)`
* Replaced `T JsonObject::get<T>(k)` with `JsonVariant JsonObject::get(k)`
* Added `JSON_STRING_SIZE()`
* ~~Replacing or removing a value now releases the memory~~
* Added `DeserializationError::code()` to be used in switch statements (issue #846)
v6.5.0-beta (2018-10-13)
-----------
* Added implicit conversion from `JsonArray` and `JsonObject` to `JsonVariant`
* Allow mixed configuration in compilation units (issue #809)
* Fixed object keys not being duplicated
* `JsonPair::key()` now returns a `JsonKey`
* Increased the default capacity of `DynamicJsonDocument`
* Fixed `JsonVariant::is<String>()` (closes #763)
* Added `JsonArrayConst`, `JsonObjectConst`, and `JsonVariantConst`
* Added copy-constructor and copy-assignment-operator for `JsonDocument` (issue #827)
v6.4.0-beta (2018-09-11)
-----------
* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780)
* Added `JsonVariant::to<JsonArray>()` and `JsonVariant::to<JsonObject>()`
v6.3.0-beta (2018-08-31)
-----------
* Implemented reference semantics for `JsonVariant`
* Replaced `JsonPair`'s `key` and `value` with `key()` and `value()`
* Fixed `serializeJson(obj[key], dst)` (issue #794)
> ### BREAKING CHANGES
>
> #### JsonVariant
>
> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
> It's a reference to a value stored in the `JsonDocument`.
> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
>
> Old code:
>
> ```c++
> JsonVariant myValue = 42;
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc;
> JsonVariant myValue = doc.to<JsonVariant>();
> myValue.set(42);
> ```
>
> #### JsonPair
>
> Old code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key);
> Serial.println(p.value.as<int>());
> }
> ```
>
> New code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key());
> Serial.println(p.value().as<int>());
> }
> ```
>
> CAUTION: the key is now read only!
v6.2.3-beta (2018-07-19)
-----------
* Fixed exception when using Flash strings as object keys (issue #784)
v6.2.2-beta (2018-07-18)
-----------
* Fixed `invalid application of 'sizeof' to incomplete type '__FlashStringHelper'` (issue #783)
* Fixed `char[]` not duplicated when passed to `JsonVariant::operator[]`
v6.2.1-beta (2018-07-17)
-----------
* Fixed `JsonObject` not inserting keys of type `String` (issue #782)
v6.2.0-beta (2018-07-12)
-----------
* Disabled lazy number deserialization (issue #772)
* Fixed `JsonVariant::is<int>()` that returned true for empty strings
* Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES
>
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys.
> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
>
> #### Preformatted values
>
> Old code:
>
> ```c++
> object["values"] = RawJson("[1,2,3,4]");
> ```
>
> New code:
>
> ```c++
> object["values"] = serialized("[1,2,3,4]");
> ```
v6.1.0-beta (2018-07-02)
-----------
* Return `JsonArray` and `JsonObject` by value instead of reference (issue #309)
* Replaced `success()` with `isNull()`
> ### BREAKING CHANGES
>
> Old code:
>
> ```c++
> JsonObject& obj = doc.to<JsonObject>();
> JsonArray& arr = obj.createNestedArray("key");
> if (!arr.success()) {
> Serial.println("Not enough memory");
> return;
> }
> ```
>
> New code:
>
> ```c++
> JsonObject obj = doc.to<JsonObject>();
> JsonArray arr = obj.createNestedArray("key");
> if (arr.isNull()) {
> Serial.println("Not enough memory");
> return;
> }
> ```
v6.0.1-beta (2018-06-11)
-----------
* Fixed conflicts with `isnan()` and `isinf()` macros (issue #752)
v6.0.0-beta (2018-06-07)
-----------
* Added `DynamicJsonDocument` and `StaticJsonDocument`
* Added `deserializeJson()`
* Added `serializeJson()` and `serializeJsonPretty()`
* Added `measureJson()` and `measureJsonPretty()`
* Added `serializeMsgPack()`, `deserializeMsgPack()` and `measureMsgPack()` (issue #358)
* Added example `MsgPackParser.ino` (issue #358)
* Added support for non zero-terminated strings (issue #704)
* Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()`
* Removed `JsonBuffer::createArray()` and `createObject()`
* Removed `printTo()` and `prettyPrintTo()`
* Removed `measureLength()` and `measurePrettyLength()`
* Removed all deprecated features
> ### BREAKING CHANGES
>
> #### Deserialization
>
> Old code:
>
> ```c++
> DynamicJsonBuffer jb;
> JsonObject& obj = jb.parseObject(json);
> if (obj.success()) {
>
> }
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc;
> DeserializationError error = deserializeJson(doc, json);
> if (error) {
>
> }
> JsonObject& obj = doc.as<JsonObject>();
> ```
>
> #### Serialization
>
> Old code:
>
> ```c++
> DynamicJsonBuffer jb;
> JsonObject& obj = jb.createObject();
> obj["key"] = "value";
> obj.printTo(Serial);
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument obj;
> JsonObject& obj = doc.to<JsonObject>();
> obj["key"] = "value";
> serializeJson(doc, Serial);
> ``` > ```

2
lib/ArduinoJson/LICENSE.txt Normal file → Executable file
View File

@@ -1,7 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
--------------------- ---------------------
Copyright © 2014-2023, Benoit BLANCHON Copyright © 2014-2024, Benoit BLANCHON
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

76
lib/ArduinoJson/README.md Normal file → Executable file
View File

@@ -4,13 +4,10 @@
--- ---
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=7.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/7.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) [![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/7.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.21.3&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.21.3)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.21.3)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.3)
[![ESP IDF](https://img.shields.io/static/v1?label=ESP+IDF&message=v6.21.3&logo=cpu&logoColor=white&color=blue)](https://components.espressif.com/components/bblanchon/arduinojson)
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers) [![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon) [![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon)
@@ -18,31 +15,28 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
## Features ## Features
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/) * [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/) * [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/api/config/decode_unicode/)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/) * [Optionally supports comments in the input](https://arduinojson.org/v7/api/config/enable_comments/)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/) * [Optionally filters the input to keep only desired values](https://arduinojson.org/v7/api/json/deserializejson/#filtering)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
* Supports single quotes as a string delimiter * Supports single quotes as a string delimiter
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/) * Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/) * [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/) * [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/) * [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/) * [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/) * [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
* Efficient * Efficient
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/) * [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/) * [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/) * [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/) * [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
* Versatile * Versatile
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/) * Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/) * Supports [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/) * Supports [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/) * Supports [Flash strings](https://arduinojson.org/v7/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer) * Supports [custom readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/) * Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
* Portable * Portable
* Usable on any C++ project (not limited to Arduino) * Usable on any C++ project (not limited to Arduino)
@@ -72,29 +66,29 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Visual Micro](http://www.visualmicro.com/) * [Visual Micro](http://www.visualmicro.com/)
* [Visual Studio](https://www.visualstudio.com/) * [Visual Studio](https://www.visualstudio.com/)
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN) * [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/) * [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
* Well designed * Well designed
* [Elegant API](http://arduinojson.org/v6/example/) * [Elegant API](http://arduinojson.org/v7/example/)
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety) * [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
* Self-contained (no external dependency) * Self-contained (no external dependency)
* `const` friendly * `const` friendly
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/) * [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming) * [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows) * Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
* Well tested * Well tested
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) * [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
* Continuously tested on * Continuously tested on
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) * [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) * [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) * [Clang 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10, 11, 12, 13, 14, 15](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) * [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/) * Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented * Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/) * [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
* [Examples](https://arduinojson.org/v6/example/) * [Examples](https://arduinojson.org/v7/example/)
* [How-tos](https://arduinojson.org/v6/example/) * [How-tos](https://arduinojson.org/v7/example/)
* [FAQ](https://arduinojson.org/v6/faq/) * [FAQ](https://arduinojson.org/v7/faq/)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/) * [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
* [Book](https://arduinojson.org/book/) * [Book](https://arduinojson.org/book/)
* [Changelog](CHANGELOG.md) * [Changelog](CHANGELOG.md)
* Vibrant user community * Vibrant user community
@@ -109,9 +103,9 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
Here is a program that parses a JSON document with ArduinoJson. Here is a program that parses a JSON document with ArduinoJson.
```c++ ```c++
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
DynamicJsonDocument doc(1024); JsonDocument doc;
deserializeJson(doc, json); deserializeJson(doc, json);
const char* sensor = doc["sensor"]; const char* sensor = doc["sensor"];
@@ -120,14 +114,14 @@ double latitude = doc["data"][0];
double longitude = doc["data"][1]; double longitude = doc["data"][1];
``` ```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/) See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
### Serialization ### Serialization
Here is a program that generates a JSON document with ArduinoJson: Here is a program that generates a JSON document with ArduinoJson:
```c++ ```c++
DynamicJsonDocument doc(1024); JsonDocument doc;
doc["sensor"] = "gps"; doc["sensor"] = "gps";
doc["time"] = 1351824120; doc["time"] = 1351824120;
@@ -139,7 +133,7 @@ serializeJson(doc, Serial);
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
``` ```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/) See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
## Sponsors ## Sponsors

27
lib/ArduinoJson/SUPPORT.md Executable file
View File

@@ -0,0 +1,27 @@
# ArduinoJson Support
First off, thank you very much for using ArduinoJson.
We'll be very happy to help you, but first please read the following.
## Before asking for help
1. Read the [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=support)
2. Search in the [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=support)
If you did not find the answer, please create a [new issue on GitHub](https://github.com/bblanchon/ArduinoJson/issues/new).
It is OK to add a comment to a currently opened issue, but please avoid adding comments to a closed issue.
## Before hitting the Submit button
Please provide all the relevant information:
* Good title
* Short description of the problem
* Target platform
* Compiler model and version
* [MVCE](https://stackoverflow.com/help/mcve)
* Compiler output
Good questions get fast answers!

View File

@@ -1,40 +0,0 @@
# Macros
JSON_ARRAY_SIZE KEYWORD2
JSON_OBJECT_SIZE KEYWORD2
JSON_STRING_SIZE KEYWORD2
# Free functions
deserializeJson KEYWORD2
deserializeMsgPack KEYWORD2
serialized KEYWORD2
serializeJson KEYWORD2
serializeJsonPretty KEYWORD2
serializeMsgPack KEYWORD2
measureJson KEYWORD2
measureJsonPretty KEYWORD2
measureMsgPack KEYWORD2
# Methods
add KEYWORD2
as KEYWORD2
createNestedArray KEYWORD2
createNestedObject KEYWORD2
get KEYWORD2
set KEYWORD2
to KEYWORD2
# Type names
DeserializationError KEYWORD1 DATA_TYPE
DynamicJsonDocument KEYWORD1 DATA_TYPE
JsonArray KEYWORD1 DATA_TYPE
JsonArrayConst KEYWORD1 DATA_TYPE
JsonDocument KEYWORD1 DATA_TYPE
JsonFloat KEYWORD1 DATA_TYPE
JsonInteger KEYWORD1 DATA_TYPE
JsonObject KEYWORD1 DATA_TYPE
JsonObjectConst KEYWORD1 DATA_TYPE
JsonString KEYWORD1 DATA_TYPE
JsonUInt KEYWORD1 DATA_TYPE
JsonVariant KEYWORD1 DATA_TYPE
JsonVariantConst KEYWORD1 DATA_TYPE
StaticJsonDocument KEYWORD1 DATA_TYPE

View File

@@ -1,11 +0,0 @@
name=ArduinoJson
version=6.21.3
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++.
paragraph=ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, ✔ filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.
category=Data Processing
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
architectures=*
repository=https://github.com/bblanchon/ArduinoJson.git
license=MIT

2
lib/ArduinoJson/src/ArduinoJson.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

13
lib/ArduinoJson/src/ArduinoJson.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -30,18 +30,19 @@
#include "ArduinoJson/Object/JsonObject.hpp" #include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/JsonVariantConst.hpp" #include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp" #include "ArduinoJson/Document/JsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp" #include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp" #include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp" #include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp" #include "ArduinoJson/Memory/VariantPoolImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp" #include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp" #include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp" #include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
#include "ArduinoJson/Json/JsonDeserializer.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp" #include "ArduinoJson/Json/JsonSerializer.hpp"

View File

@@ -0,0 +1,57 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayData : public CollectionData {
public:
VariantData* addElement(ResourceManager* resources) {
return addSlot(resources).data();
}
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
if (!array)
return nullptr;
return array->addElement(resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
VariantData* getElement(size_t index, const ResourceManager* resources) const;
static VariantData* getElement(const ArrayData* array, size_t index,
const ResourceManager* resources) {
if (!array)
return nullptr;
return array->getElement(index, resources);
}
void removeElement(size_t index, ResourceManager* resources);
static void removeElement(ArrayData* array, size_t index,
ResourceManager* resources) {
if (!array)
return;
array->removeElement(index, resources);
}
bool copyFrom(const ArrayData& src, ResourceManager* resources);
static bool copy(ArrayData* dst, const ArrayData* src,
ResourceManager* resources) {
if (!dst || !src)
return false;
return dst->copyFrom(*src, resources);
}
private:
iterator at(size_t index, const ResourceManager* resources) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,50 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(
size_t index, const ResourceManager* resources) const {
auto it = createIterator(resources);
while (!it.done() && index) {
it.next(resources);
--index;
}
return it;
}
inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) {
auto it = createIterator(resources);
while (!it.done() && index > 0) {
it.next(resources);
index--;
}
if (it.done())
index++;
VariantData* element = it.data();
while (index > 0) {
element = addElement(resources);
if (!element)
return nullptr;
index--;
}
return element;
}
inline VariantData* ArrayData::getElement(
size_t index, const ResourceManager* resources) const {
return at(index, resources).data();
}
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index, resources), resources);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

27
lib/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -9,7 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// A proxy class to get or set an element of an array. // A proxy class to get or set an element of an array.
// https://arduinojson.org/v6/api/jsonarray/subscript/ // https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename TUpstream> template <typename TUpstream>
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>, class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
public VariantOperators<ElementProxy<TUpstream>> { public VariantOperators<ElementProxy<TUpstream>> {
@@ -22,35 +22,40 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
ElementProxy(const ElementProxy& src) ElementProxy(const ElementProxy& src)
: upstream_(src.upstream_), index_(src.index_) {} : upstream_(src.upstream_), index_(src.index_) {}
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) { ElementProxy& operator=(const ElementProxy& src) {
this->set(src); this->set(src);
return *this; return *this;
} }
template <typename T> template <typename T>
FORCE_INLINE ElementProxy& operator=(const T& src) { ElementProxy& operator=(const T& src) {
this->set(src); this->set(src);
return *this; return *this;
} }
template <typename T> template <typename T>
FORCE_INLINE ElementProxy& operator=(T* src) { ElementProxy& operator=(T* src) {
this->set(src); this->set(src);
return *this; return *this;
} }
private: private:
FORCE_INLINE MemoryPool* getPool() const { ResourceManager* getResourceManager() const {
return VariantAttorney::getPool(upstream_); return VariantAttorney::getResourceManager(upstream_);
} }
FORCE_INLINE VariantData* getData() const { FORCE_INLINE VariantData* getData() const {
return variantGetElement(VariantAttorney::getData(upstream_), index_); return VariantData::getElement(
VariantAttorney::getData(upstream_), index_,
VariantAttorney::getResourceManager(upstream_));
} }
FORCE_INLINE VariantData* getOrCreateData() const { VariantData* getOrCreateData() const {
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_), auto data = VariantAttorney::getOrCreateData(upstream_);
index_, VariantAttorney::getPool(upstream_)); if (!data)
return nullptr;
return data->getOrAddElement(
index_, VariantAttorney::getResourceManager(upstream_));
} }
TUpstream upstream_; TUpstream upstream_;

201
lib/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject; class JsonObject;
// A reference to an array in a JsonDocument // A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/ // https://arduinojson.org/v7/api/jsonarray/
class JsonArray : public detail::VariantOperators<JsonArray> { class JsonArray : public detail::VariantOperators<JsonArray> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -20,155 +20,165 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
typedef JsonArrayIterator iterator; typedef JsonArrayIterator iterator;
// Constructs an unbound reference. // Constructs an unbound reference.
FORCE_INLINE JsonArray() : data_(0), pool_(0) {} JsonArray() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data) JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
: data_(data), pool_(pool) {} : data_(data), resources_(resources) {}
// Returns a JsonVariant pointing to the array. // Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/ // https://arduinojson.org/v7/api/jsonvariant/
operator JsonVariant() { operator JsonVariant() {
void* data = data_; // prevent warning cast-align void* data = data_; // prevent warning cast-align
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data)); return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
} }
// Returns a read-only reference to the array. // Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const { operator JsonArrayConst() const {
return JsonArrayConst(data_); return JsonArrayConst(data_, resources_);
}
// Appends a new (empty) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() const {
return add<JsonVariant>().to<T>();
} }
// Appends a new (null) element to the array. // Appends a new (null) element to the array.
// Returns a reference to the new element. // Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
JsonVariant add() const { template <typename T>
if (!data_) typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
return JsonVariant(); add() const {
return JsonVariant(pool_, data_->addElement(pool_)); return JsonVariant(detail::ArrayData::addElement(data_, resources_),
resources_);
} }
// Appends a value to the array. // Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
FORCE_INLINE bool add(const T& value) const { bool add(const T& value) const {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Appends a value to the array. // Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
FORCE_INLINE bool add(T* value) const { bool add(T* value) const {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/ // https://arduinojson.org/v7/api/jsonarray/begin/
FORCE_INLINE iterator begin() const { iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(pool_, data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator following the last element of the array. // Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/ // https://arduinojson.org/v7/api/jsonarray/end/
FORCE_INLINE iterator end() const { iterator end() const {
return iterator(); return iterator();
} }
// Copies an array. // Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/ // https://arduinojson.org/v7/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const { bool set(JsonArrayConst src) const {
if (!data_ || !src.data_) if (!data_)
return false; return false;
return data_->copyFrom(*src.data_, pool_);
}
// Compares the content of two arrays. clear();
FORCE_INLINE bool operator==(JsonArray rhs) const { for (auto element : src) {
return JsonArrayConst(data_) == JsonArrayConst(rhs.data_); if (!add(element))
return false;
}
return true;
} }
// Removes the element at the specified iterator. // Removes the element at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsonarray/remove/
// https://arduinojson.org/v6/api/jsonarray/remove/ void remove(iterator it) const {
FORCE_INLINE void remove(iterator it) const { detail::ArrayData::remove(data_, it.iterator_, resources_);
if (!data_)
return;
data_->removeSlot(it.slot_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsonarray/remove/
// https://arduinojson.org/v6/api/jsonarray/remove/ void remove(size_t index) const {
FORCE_INLINE void remove(size_t index) const { detail::ArrayData::removeElement(data_, index, resources_);
if (!data_)
return;
data_->removeElement(index);
} }
// Removes all the elements of the array. // Removes all the elements of the array.
// ⚠️ Doesn't release the memory associated with the removed elements. // https://arduinojson.org/v7/api/jsonarray/clear/
// https://arduinojson.org/v6/api/jsonarray/clear/
void clear() const { void clear() const {
if (!data_) detail::ArrayData::clear(data_, resources_);
return;
data_->clear();
} }
// Gets or sets the element at the specified index. // Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/ // https://arduinojson.org/v7/api/jsonarray/subscript/
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const { detail::ElementProxy<JsonArray> operator[](size_t index) const {
return {*this, index}; return {*this, index};
} }
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
}
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(collectionToVariant(data_), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const { bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
FORCE_INLINE operator bool() const { operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/ // https://arduinojson.org/v7/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const { size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(collectionToVariant(data_), resources_);
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/ // https://arduinojson.org/v7/api/jsonarray/size/
FORCE_INLINE size_t size() const { size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() const {
return add<JsonVariant>();
}
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() const {
return add<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() const;
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
} }
private: private:
detail::MemoryPool* getPool() const { detail::ResourceManager* getResourceManager() const {
return pool_; return resources_;
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
@@ -179,33 +189,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return collectionToVariant(data_); return collectionToVariant(data_);
} }
detail::CollectionData* data_; detail::ArrayData* data_;
detail::MemoryPool* pool_; detail::ResourceManager* resources_;
};
template <>
struct Converter<JsonArray> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isArray();
}
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

122
lib/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject; class JsonObject;
// A read-only reference to an array in a JsonDocument // A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> { class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
friend class JsonArray; friend class JsonArray;
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -22,89 +22,66 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
typedef JsonArrayConstIterator iterator; typedef JsonArrayConstIterator iterator;
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/ // https://arduinojson.org/v7/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const { iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator to the element following the last element of the array. // Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/ // https://arduinojson.org/v7/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const { iterator end() const {
return iterator(); return iterator();
} }
// Creates an unbound reference. // Creates an unbound reference.
FORCE_INLINE JsonArrayConst() : data_(0) {} JsonArrayConst() : data_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data) JsonArrayConst(const detail::ArrayData* data,
: data_(data) {} const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (data_ == rhs.data_)
return true;
if (!data_ || !rhs.data_)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
}
// Returns the element at the specified index. // Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/ // https://arduinojson.org/v7/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(data_ ? data_->getElement(index) : 0); return JsonVariantConst(
detail::ArrayData::getElement(data_, index, resources_), resources_);
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(getData(), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const { bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const { operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/ // https://arduinojson.org/v7/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const { size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(getData(), resources_);
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/ // https://arduinojson.org/v7/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const { size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
} }
private: private:
@@ -112,24 +89,31 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
return collectionToVariant(data_); return collectionToVariant(data_);
} }
const detail::CollectionData* data_; const detail::ArrayData* data_;
const detail::ResourceManager* resources_;
}; };
template <> // Compares the content of two arrays.
struct Converter<JsonArrayConst> : private detail::VariantAttorney { // Returns true if the two arrays are equal.
static void toJson(JsonVariantConst src, JsonVariant dst) { inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); if (!lhs && !rhs)
} return true;
if (!lhs || !rhs)
return false;
static JsonArrayConst fromJson(JsonVariantConst src) { auto a = lhs.begin();
auto data = getData(src); auto b = rhs.begin();
return data ? data->asArray() : 0;
}
static bool checkJson(JsonVariantConst src) { for (;;) {
auto data = getData(src); if (a == b) // same pointer or both null
return data && data->isArray(); return true;
if (a == lhs.end() || b == rhs.end())
return false;
if (*a != *b)
return false;
++a;
++b;
} }
}; }
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,36 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,121 +1,96 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp> #include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class VariantPtr { template <typename T>
class Ptr {
public: public:
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data) Ptr(T value) : value_(value) {}
: variant_(pool, data) {}
JsonVariant* operator->() { T* operator->() {
return &variant_; return &value_;
} }
JsonVariant& operator*() { T& operator*() {
return variant_; return value_;
} }
private: private:
JsonVariant variant_; T value_;
}; };
class JsonArrayIterator { class JsonArrayIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayIterator() : slot_(0) {} JsonArrayIterator() {}
explicit JsonArrayIterator(detail::MemoryPool* pool, explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
detail::VariantSlot* slot) detail::ResourceManager* resources)
: pool_(pool), slot_(slot) {} : iterator_(iterator), resources_(resources) {}
JsonVariant operator*() const { JsonVariant operator*() {
return JsonVariant(pool_, slot_->data()); return JsonVariant(iterator_.data(), resources_);
} }
VariantPtr operator->() { Ptr<JsonVariant> operator->() {
return VariantPtr(pool_, slot_->data()); return operator*();
} }
bool operator==(const JsonArrayIterator& other) const { bool operator==(const JsonArrayIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayIterator& other) const { bool operator!=(const JsonArrayIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayIterator& operator++() { JsonArrayIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
detail::MemoryPool* pool_; detail::ArrayData::iterator iterator_;
detail::VariantSlot* slot_; detail::ResourceManager* resources_;
};
class VariantConstPtr {
public:
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
JsonVariantConst* operator->() {
return &variant_;
}
JsonVariantConst& operator*() {
return variant_;
}
private:
JsonVariantConst variant_;
}; };
class JsonArrayConstIterator { class JsonArrayConstIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayConstIterator() : slot_(0) {} JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(const detail::VariantSlot* slot) explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
: slot_(slot) {} const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariantConst operator*() const { JsonVariantConst operator*() const {
return JsonVariantConst(slot_->data()); return JsonVariantConst(iterator_.data(), resources_);
} }
VariantConstPtr operator->() { Ptr<JsonVariantConst> operator->() {
return VariantConstPtr(slot_->data()); return operator*();
} }
bool operator==(const JsonArrayConstIterator& other) const { bool operator==(const JsonArrayConstIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayConstIterator& other) const { bool operator!=(const JsonArrayConstIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayConstIterator& operator++() { JsonArrayConstIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
const detail::VariantSlot* slot_; detail::ArrayData::iterator iterator_;
const detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

18
lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -18,7 +18,7 @@ copyArray(const T& src, JsonVariant dst) {
} }
// Copies values from an array to a JsonArray or a JsonVariant. // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N, typename TDestination> template <typename T, size_t N, typename TDestination>
inline typename detail::enable_if< inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
@@ -27,14 +27,14 @@ copyArray(T (&src)[N], const TDestination& dst) {
} }
// Copies values from an array to a JsonArray or a JsonVariant. // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, typename TDestination> template <typename T, typename TDestination>
inline typename detail::enable_if< inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) { copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true; bool ok = true;
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.add()); ok &= copyArray(src[i], dst.template add<JsonVariant>());
} }
return ok; return ok;
} }
@@ -47,14 +47,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
} }
// Copies values from an array to a JsonDocument. // Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) { inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<JsonArray>()); return copyArray(src, dst.to<JsonArray>());
} }
// Copies an array to a JsonDocument. // Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<JsonArray>()); return copyArray(src, len, dst.to<JsonArray>());
@@ -70,14 +70,14 @@ copyArray(JsonVariantConst src, T& dst) {
} }
// Copies values from a JsonArray or JsonVariant to an array. // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N> template <typename T, size_t N>
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) { inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N); return copyArray(src, dst, N);
} }
// Copies values from a JsonArray or JsonVariant to an array. // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) { inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0; size_t i = 0;
@@ -101,7 +101,7 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
} }
// Copies values from a JsonDocument to an array. // Copies values from a JsonDocument to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename TSource, typename T> template <typename TSource, typename T>
inline typename detail::enable_if< inline typename detail::enable_if<
detail::is_array<T>::value && detail::is_array<T>::value &&

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -11,74 +11,112 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class MemoryPool;
class VariantData; class VariantData;
class VariantSlot; class VariantSlot;
class CollectionData { class CollectionIterator {
VariantSlot* head_; friend class CollectionData;
VariantSlot* tail_;
public: public:
// Must be a POD! CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
// - no constructor
// - no destructor
// - no virtual
// - no inheritance
// Array only void next(const ResourceManager* resources);
VariantData* addElement(MemoryPool* pool); bool done() const {
return slot_ == nullptr;
VariantData* getElement(size_t index) const;
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
void removeElement(size_t index);
// Object only
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {
removeSlot(getSlot(key));
} }
template <typename TAdaptedString> bool operator==(const CollectionIterator& other) const {
bool containsKey(const TAdaptedString& key) const; return slot_ == other.slot_;
}
// Generic bool operator!=(const CollectionIterator& other) const {
return slot_ != other.slot_;
}
void clear(); VariantData* operator->() {
size_t memoryUsage() const; ARDUINOJSON_ASSERT(slot_ != nullptr);
size_t size() const; return data();
}
VariantSlot* addSlot(MemoryPool*); VariantData& operator*() {
void removeSlot(VariantSlot* slot); ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
bool copyFrom(const CollectionData& src, MemoryPool* pool); const VariantData& operator*() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
VariantSlot* head() const { const char* key() const;
bool ownsKey() const;
void setKey(StringNode*);
void setKey(const char*);
VariantData* data() {
return reinterpret_cast<VariantData*>(slot_);
}
const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_);
}
private:
CollectionIterator(VariantSlot* slot, SlotId slotId);
VariantSlot* slot_;
SlotId currentId_, nextId_;
};
class CollectionData {
SlotId head_ = NULL_SLOT;
SlotId tail_ = NULL_SLOT;
public:
// Placement new
static void* operator new(size_t, void* p) noexcept {
return p;
}
static void operator delete(void*, void*) noexcept {}
using iterator = CollectionIterator;
iterator createIterator(const ResourceManager* resources) const {
return iterator(resources->getSlot(head_), head_);
}
size_t size(const ResourceManager*) const;
size_t nesting(const ResourceManager*) const;
void clear(ResourceManager* resources);
static void clear(CollectionData* collection, ResourceManager* resources) {
if (!collection)
return;
collection->clear(resources);
}
void remove(iterator it, ResourceManager* resources);
static void remove(CollectionData* collection, iterator it,
ResourceManager* resources) {
if (collection)
return collection->remove(it, resources);
}
SlotId head() const {
return head_; return head_;
} }
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); protected:
iterator addSlot(ResourceManager*);
private: private:
VariantSlot* getSlot(size_t index) const; SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
void releaseSlot(SlotWithId, ResourceManager*);
template <typename TAdaptedString>
VariantSlot* getSlot(TAdaptedString key) const;
VariantSlot* getPreviousSlot(VariantSlot*) const;
}; };
inline const VariantData* collectionToVariant( inline const VariantData* collectionToVariant(

View File

@@ -1,197 +1,133 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Collection/CollectionData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId)
VariantSlot* slot = pool->allocVariant(); : slot_(slot), currentId_(slotId) {
if (!slot) nextId_ = slot_ ? slot_->next() : NULL_SLOT;
return 0; }
if (tail_) { inline const char* CollectionIterator::key() const {
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object ARDUINOJSON_ASSERT(slot_ != nullptr);
tail_->setNextNotNull(slot); return slot_->key();
tail_ = slot; }
inline void CollectionIterator::setKey(const char* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline void CollectionIterator::setKey(StringNode* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline bool CollectionIterator::ownsKey() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->ownsKey();
}
inline void CollectionIterator::next(const ResourceManager* resources) {
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
slot_ = resources->getSlot(nextId_);
currentId_ = nextId_;
if (slot_)
nextId_ = slot_->next();
}
inline CollectionData::iterator CollectionData::addSlot(
ResourceManager* resources) {
auto slot = resources->allocSlot();
if (!slot)
return {};
if (tail_ != NULL_SLOT) {
auto tail = resources->getSlot(tail_);
tail->setNext(slot.id());
tail_ = slot.id();
} else { } else {
head_ = slot; head_ = slot.id();
tail_ = slot; tail_ = slot.id();
}
return iterator(slot, slot.id());
}
inline void CollectionData::clear(ResourceManager* resources) {
auto next = head_;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = resources->getSlot(next);
next = slot->next();
releaseSlot(SlotWithId(slot, currId), resources);
} }
slot->clear(); head_ = NULL_SLOT;
return slot; tail_ = NULL_SLOT;
} }
inline VariantData* CollectionData::addElement(MemoryPool* pool) { inline SlotWithId CollectionData::getPreviousSlot(
return slotData(addSlot(pool)); VariantSlot* target, const ResourceManager* resources) const {
} auto prev = SlotWithId();
auto currentId = head_;
template <typename TAdaptedString> while (currentId != NULL_SLOT) {
inline VariantData* CollectionData::addMember(TAdaptedString key, auto currentSlot = resources->getSlot(currentId);
MemoryPool* pool) { if (currentSlot == target)
VariantSlot* slot = addSlot(pool); return prev;
if (!slotSetKey(slot, key, pool)) { prev = SlotWithId(currentSlot, currentId);
removeSlot(slot); currentId = currentSlot->next();
return 0;
} }
return slot->data(); return SlotWithId();
} }
inline void CollectionData::clear() { inline void CollectionData::remove(iterator it, ResourceManager* resources) {
head_ = 0; if (it.done())
tail_ = 0;
}
template <typename TAdaptedString>
inline bool CollectionData::containsKey(const TAdaptedString& key) const {
return getSlot(key) != 0;
}
inline bool CollectionData::copyFrom(const CollectionData& src,
MemoryPool* pool) {
clear();
for (VariantSlot* s = src.head_; s; s = s->next()) {
VariantData* var;
if (s->key() != 0) {
JsonString key(s->key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else {
var = addElement(pool);
}
if (!var)
return false;
if (!var->copyFrom(*s->data(), pool))
return false;
}
return true;
}
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
return 0;
VariantSlot* slot = head_;
while (slot) {
if (stringEquals(key, adaptString(slot->key())))
break;
slot = slot->next();
}
return slot;
}
inline VariantSlot* CollectionData::getSlot(size_t index) const {
if (!head_)
return 0;
return head_->next(index);
}
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
VariantSlot* current = head_;
while (current) {
VariantSlot* next = current->next();
if (next == target)
return current;
current = next;
}
return 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
VariantSlot* slot = getSlot(key);
return slot ? slot->data() : 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
// ignore null key
if (key.isNull())
return 0;
// search a matching key
VariantSlot* slot = getSlot(key);
if (slot)
return slot->data();
return addMember(key, pool);
}
inline VariantData* CollectionData::getElement(size_t index) const {
VariantSlot* slot = getSlot(index);
return slot ? slot->data() : 0;
}
inline VariantData* CollectionData::getOrAddElement(size_t index,
MemoryPool* pool) {
VariantSlot* slot = head_;
while (slot && index > 0) {
slot = slot->next();
index--;
}
if (!slot)
index++;
while (index > 0) {
slot = addSlot(pool);
index--;
}
return slotData(slot);
}
inline void CollectionData::removeSlot(VariantSlot* slot) {
if (!slot)
return; return;
VariantSlot* prev = getPreviousSlot(slot); auto curr = it.slot_;
VariantSlot* next = slot->next(); auto prev = getPreviousSlot(curr, resources);
auto next = curr->next();
if (prev) if (prev)
prev->setNext(next); prev->setNext(next);
else else
head_ = next; head_ = next;
if (!next) if (next == NULL_SLOT)
tail_ = prev; tail_ = prev.id();
releaseSlot({it.slot_, it.currentId_}, resources);
} }
inline void CollectionData::removeElement(size_t index) { inline size_t CollectionData::nesting(const ResourceManager* resources) const {
removeSlot(getSlot(index)); size_t maxChildNesting = 0;
} for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
size_t childNesting = it->nesting(resources);
inline size_t CollectionData::memoryUsage() const { if (childNesting > maxChildNesting)
size_t total = 0; maxChildNesting = childNesting;
for (VariantSlot* s = head_; s; s = s->next()) {
total += sizeof(VariantSlot) + s->data()->memoryUsage();
if (s->ownsKey())
total += strlen(s->key()) + 1;
} }
return total; return maxChildNesting + 1;
} }
inline size_t CollectionData::size() const { inline size_t CollectionData::size(const ResourceManager* resources) const {
return slotSize(head_); size_t count = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources))
count++;
return count;
} }
template <typename T> inline void CollectionData::releaseSlot(SlotWithId slot,
inline void movePointer(T*& p, ptrdiff_t offset) { ResourceManager* resources) {
if (!p) if (slot->ownsKey())
return; resources->dereferenceString(slot->key());
p = reinterpret_cast<T*>( slot->data()->setNull(resources);
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset)); resources->freeSlot(slot);
ARDUINOJSON_ASSERT(isAligned(p));
}
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
ptrdiff_t variantDistance) {
movePointer(head_, variantDistance);
movePointer(tail_, variantDistance);
for (VariantSlot* slot = head_; slot; slot = slot->next())
slot->movePointers(stringDistance, variantDistance);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

82
lib/ArduinoJson/src/ArduinoJson/Configuration.hpp Normal file → Executable file
View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -59,15 +59,24 @@
# define ARDUINOJSON_USE_DOUBLE 1 # define ARDUINOJSON_USE_DOUBLE 1
#endif #endif
// Store integral values with long (0) or long long (1) // Pointer size: a heuristic to set sensible defaults
#ifndef ARDUINOJSON_USE_LONG_LONG #ifndef ARDUINOJSON_SIZEOF_POINTER
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \ # if defined(__SIZEOF_POINTER__)
defined(_MSC_VER) # define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
# define ARDUINOJSON_USE_LONG_LONG 1 # elif defined(_WIN64) && _WIN64
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
# else
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
# endif # endif
#endif #endif
// Store integral values with long (0) or long long (1)
#ifndef ARDUINOJSON_USE_LONG_LONG #ifndef ARDUINOJSON_USE_LONG_LONG
# define ARDUINOJSON_USE_LONG_LONG 0 # if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
# define ARDUINOJSON_USE_LONG_LONG 1
# else
# define ARDUINOJSON_USE_LONG_LONG 0
# endif
#endif #endif
// Limit nesting as the stack is likely to be small // Limit nesting as the stack is likely to be small
@@ -75,19 +84,50 @@
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif #endif
// Number of bits to store the pointer to next node // Number of bytes to store the variant identifier
// (saves RAM but limits the number of values in a document) #ifndef ARDUINOJSON_SLOT_ID_SIZE
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE # if ARDUINOJSON_SIZEOF_POINTER <= 2
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2 # define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots
// Address space == 16-bit => max 127 values # elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1 # define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
defined(_WIN64) && _WIN64
// Address space == 64-bit => max 2147483647 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
# else # else
// Address space == 32-bit => max 32767 values # define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2 # endif
#endif
// Capacity of each variant pool (in slots)
#ifndef ARDUINOJSON_POOL_CAPACITY
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes
# elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes
# else
# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes
# endif
#endif
// Initial capacity of the pool list
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
#endif
// Automatically call shrinkToFit() from deserializeXxx()
// Disabled by default on 8-bit platforms because it's not worth the increase in
// code size
#ifndef ARDUINOJSON_AUTO_SHRINK
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_AUTO_SHRINK 0
# else
# define ARDUINOJSON_AUTO_SHRINK 1
# endif
#endif
// Number of bytes to store the length of a string
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
# else
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
# endif # endif
#endif #endif
@@ -195,10 +235,6 @@
# define ARDUINOJSON_TAB " " # define ARDUINOJSON_TAB " "
#endif #endif
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
#endif
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE #ifndef ARDUINOJSON_STRING_BUFFER_SIZE
# define ARDUINOJSON_STRING_BUFFER_SIZE 32 # define ARDUINOJSON_STRING_BUFFER_SIZE 32
#endif #endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,17 +1,24 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
namespace DeserializationOption { namespace DeserializationOption {
class Filter { class Filter {
public: public:
explicit Filter(JsonVariantConst v) : variant_(v) {} #if ARDUINOJSON_AUTO_SHRINK
explicit Filter(JsonDocument& doc) : variant_(doc) {
doc.shrinkToFit();
}
#endif
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
bool allow() const { bool allow() const {
return variant_; return variant_;

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -19,7 +19,7 @@ struct Reader {
int read() { int read() {
// clang-format off // clang-format off
return source_->read(); // Error here? See https://arduinojson.org/v6/invalid-input/ return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
// clang-format on // clang-format on
} }

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -15,7 +15,7 @@ struct Reader<TSource,
explicit Reader(Stream& stream) : stream_(&stream) {} explicit Reader(Stream& stream) : stream_(&stream) {}
int read() { int read() {
// don't use stream_.read() as it ignores the timeout // don't use stream_->read() as it ignores the timeout
char c; char c;
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
} }

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

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