diff --git a/Makefile b/Makefile index c1ca05b90..ba1d304d8 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,9 @@ CXX_STANDARD := -std=gnu++17 #---------------------------------------------------------------------- # Defined Symbols #---------------------------------------------------------------------- -DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 +DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500 +DEFINES += -DNO_TLS_SUPPORT DEFINES += $(ARGS) DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" @@ -79,6 +80,10 @@ SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null) CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null) +# Exclude files not needed for standalone build, if they exist +CSOURCES := $(filter-out src/core/ModuleLibrary.c,$(CSOURCES)) +CXXSOURCES := $(filter-out src/core/ModuleLibrary.cpp,$(CXXSOURCES)) + OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES))) DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES))) diff --git a/data/pre_load.json b/data/pre_load.json index 9c0ad34cc..cd5fdd2c7 100644 --- a/data/pre_load.json +++ b/data/pre_load.json @@ -1,85 +1,228 @@ { - "type": "settings", - "Network": { - "ssid": "my_wifi_ssid", - "bssid": "", - "password": "my_wifi_password", - "hostname": "ems-esp" + "type": "systembackup", + "version": "3.8.2", + "date": "2026-03-29T13:28:15", + "systembackup": [ + { + "type": "settings", + "Network": { + "ssid": "", + "bssid": "", + "password": "", + "hostname": "ems-esp", + "static_ip_config": false, + "bandwidth20": false, + "nosleep": true, + "enableMDNS": true, + "enableCORS": false, + "CORSOrigin": "*", + "tx_power": 0 + }, + "AP": { + "provision_mode": 2, + "ssid": "ems-esp", + "password": "ems-esp-neo", + "channel": 1, + "ssid_hidden": false, + "max_clients": 4, + "local_ip": "192.168.4.1", + "gateway_ip": "192.168.4.1", + "subnet_mask": "255.255.255.0" + }, + "MQTT": { + "enableTLS": false, + "rootCA": "", + "enabled": false, + "host": "", + "port": 1883, + "base": "ems-esp", + "username": "", + "password": "", + "client_id": "esp32-b8ffc9ec", + "keep_alive": 60, + "clean_session": false, + "entity_format": 1, + "publish_time_boiler": 10, + "publish_time_thermostat": 10, + "publish_time_solar": 10, + "publish_time_mixer": 10, + "publish_time_water": 10, + "publish_time_other": 60, + "publish_time_sensor": 10, + "publish_time_heartbeat": 60, + "mqtt_qos": 0, + "mqtt_retain": false, + "ha_enabled": false, + "nested_format": 1, + "discovery_prefix": "homeassistant", + "discovery_type": 0, + "ha_number_mode": 0, + "publish_single": false, + "publish_single2cmd": false, + "send_response": false + }, + "NTP": { + "enabled": true, + "server": "time.google.com", + "tz_label": "Europe/Amsterdam", + "tz_format": "CET-1CEST,M3.5.0,M10.5.0/3" + }, + "Security": { + "jwt_secret": "ems-esp-neo", + "users": [ + { + "username": "admin", + "password": "admin", + "admin": true + }, + { + "username": "guest", + "password": "guest", + "admin": false + } + ] + }, + "Settings": { + "version": "3.8.2", + "board_profile": "E32V2_2", + "platform": "ESP32", + "locale": "en", + "tx_mode": 1, + "ems_bus_id": 11, + "syslog_enabled": false, + "syslog_level": 3, + "trace_raw": false, + "syslog_mark_interval": 0, + "syslog_host": "", + "syslog_port": 514, + "boiler_heatingoff": false, + "remote_timeout": 24, + "remote_timeout_en": false, + "shower_timer": false, + "shower_alert": false, + "shower_alert_coldshot": 10, + "shower_alert_trigger": 7, + "shower_min_duration": 180, + "rx_gpio": 4, + "tx_gpio": 5, + "dallas_gpio": 14, + "dallas_parasite": false, + "led_gpio": 32, + "hide_led": false, + "led_type": 1, + "low_clock": false, + "telnet_enabled": true, + "notoken_api": false, + "readonly_mode": false, + "analog_enabled": true, + "pbutton_gpio": 34, + "solar_maxflow": 30, + "fahrenheit": false, + "bool_format": 1, + "bool_dashboard": 1, + "enum_format": 1, + "weblog_level": 6, + "weblog_buffer": 50, + "weblog_compact": true, + "phy_type": 1, + "eth_power": 15, + "eth_phy_addr": 0, + "eth_clock_mode": 1, + "modbus_enabled": false, + "modbus_port": 502, + "modbus_max_clients": 10, + "modbus_timeout": 300, + "developer_mode": true, + "email_enabled": false, + "email_ssl": false, + "email_starttls": true, + "email_server": "smtp.example.net", + "email_port": 587, + "email_login": "", + "email_pass": "", + "email_sender": "ems-esp@example.net", + "email_recp": "", + "email_subject": "ems-esp notification" + } }, - "AP": { - "provision_mode": 2, - "ssid": "ems-esp", - "password": "ems-esp-neo", - "channel": 1, - "ssid_hidden": false, - "max_clients": 4, - "local_ip": "192.168.4.1", - "gateway_ip": "192.168.4.1", - "subnet_mask": "255.255.255.0" + { + "type": "schedule", + "Schedule": { + "schedule": [] + } }, - "MQTT": { - "enableTLS": false, - "rootCA": "", - "enabled": false, - "host": "127.0.0.1", - "port": 1883, - "base": "ems-esp", - "username": "username", - "password": "password", - "client_id": "ems-esp", - "entity_format": 1, - "publish_time_boiler": 10, - "publish_time_thermostat": 10, - "publish_time_solar": 10, - "publish_time_mixer": 10, - "publish_time_water": 10, - "publish_time_other": 60, - "publish_time_sensor": 10, - "publish_time_heartbeat": 60, - "mqtt_qos": 0, - "mqtt_retain": false, - "ha_enabled": false, - "nested_format": 1, - "discovery_prefix": "homeassistant", - "discovery_type": 0, - "publish_single": false, - "publish_single2cmd": false, - "send_response": false + { + "type": "customizations", + "Customizations": { + "ts": [ + { + "id": "28_1767_7B13_2502", + "name": "gateway_temperature", + "offset": 0, + "is_system": true + } + ], + "as": [ + { + "gpio": 39, + "name": "core_voltage", + "offset": 0, + "factor": 0.003771, + "uom": 23, + "type": 3, + "is_system": true + }, + { + "gpio": 36, + "name": "supply_voltage", + "offset": 0, + "factor": 0.017, + "uom": 23, + "type": 3, + "is_system": true + }, + { + "gpio": 2, + "name": "led", + "offset": 0, + "factor": 1, + "uom": 0, + "type": 6, + "is_system": true + } + ], + "masked_entities": [] + } }, - "NTP": { - "enabled": true, - "server": "time.google.com", - "tz_label": "Europe/Amsterdam", - "tz_format": "CET-1CEST,M3.5.0,M10.5.0/3" + { + "type": "entities", + "Entities": { + "entities": [] + } }, - "Security": { - "jwt_secret": "ems-esp-neo", - "users": [ - { - "username": "admin", - "password": "admin", - "admin": true - }, - { - "username": "guest", - "password": "guest", - "admin": false - } - ] + { + "type": "modules", + "Modules": { + "modules": [] + } }, - "Settings": { - "board_profile": "S3", - "locale": "en", - "tx_mode": 1, - "ems_bus_id": 11, - "boiler_heatingoff": false, - "hide_led": true, - "telnet_enabled": true, - "notoken_api": false, - "analog_enabled": true, - "fahrenheit": false, - "bool_format": 1, - "bool_dashboard": 1, - "enum_format": 1 + { + "type": "customSupport", + "Support": { + "html": [ + "This product is installed and managed by:", + "", + "Bosch Installer Example", + "", + "Nefit Road 12", + "1234 AB Amsterdam", + "Phone: +31 123 456 789", + "email: support@boschinstaller.nl", + "", + "For help and questions please contact your installer." + ], + "img_url": "https://emsesp.org/media/images/designer.png" + } } - } \ No newline at end of file + ] +} \ No newline at end of file diff --git a/interface/package.json b/interface/package.json index 76c9d28cf..5776d6d2d 100644 --- a/interface/package.json +++ b/interface/package.json @@ -1,6 +1,6 @@ { "name": "EMS-ESP", - "version": "3.8.0", + "version": "3.8.2", "description": "EMS-ESP WebUI", "homepage": "https://emsesp.org", "author": "proddy, emsesp.org", @@ -26,8 +26,8 @@ "@alova/adapter-xhr": "2.3.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@mui/icons-material": "^7.3.9", - "@mui/material": "^7.3.9", + "@mui/icons-material": "^9.0.0", + "@mui/material": "^9.0.0", "@preact/compat": "^18.3.2", "@table-library/react-table-library": "4.1.15", "alova": "3.5.1", @@ -37,35 +37,35 @@ "jwt-decode": "^4.0.0", "magic-string": "^0.30.21", "mime-types": "^3.0.2", - "preact": "^10.29.0", - "react": "^19.2.4", - "react-dom": "^19.2.4", + "preact": "^10.29.1", + "react": "^19.2.5", + "react-dom": "^19.2.5", "react-icons": "^5.6.0", - "react-router": "^7.13.1", + "react-router": "^7.14.1", "react-toastify": "^11.0.5", "typesafe-i18n": "^5.27.1", - "typescript": "^5.9.3" + "typescript": "^6.0.2" }, "devDependencies": { "@babel/core": "^7.29.0", "@eslint/js": "^10.0.1", "@preact/compat": "^18.3.2", - "@preact/preset-vite": "^2.10.4", + "@preact/preset-vite": "^2.10.5", "@trivago/prettier-plugin-sort-imports": "^6.0.2", - "@types/node": "^25.5.0", + "@types/node": "^25.6.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "axe-core": "^4.11.1", + "axe-core": "^4.11.3", "concurrently": "^9.2.1", - "eslint": "^10.0.3", + "eslint": "^10.2.0", "eslint-config-prettier": "^10.1.8", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "rollup-plugin-visualizer": "^7.0.1", "terser": "^5.46.1", - "typescript-eslint": "^8.57.1", - "vite": "^7.3.1", + "typescript-eslint": "^8.58.2", + "vite": "^8.0.8", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^6.1.1" }, - "packageManager": "pnpm@10.32.1" + "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index a36b65459..ea27c1e11 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -13,22 +13,22 @@ importers: version: 2.3.1(alova@3.5.1) '@emotion/react': specifier: ^11.14.0 - version: 11.14.0(@types/react@19.2.14)(react@19.2.4) + version: 11.14.0(@types/react@19.2.14)(react@19.2.5) '@emotion/styled': specifier: ^11.14.1 - version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/icons-material': - specifier: ^7.3.9 - version: 7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + specifier: ^9.0.0 + version: 9.0.0(@mui/material@9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/material': - specifier: ^7.3.9 - version: 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^9.0.0 + version: 9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@preact/compat': specifier: ^18.3.2 - version: 18.3.2(preact@10.29.0) + version: 18.3.2(preact@10.29.1) '@table-library/react-table-library': specifier: 4.1.15 - version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) alova: specifier: 3.5.1 version: 3.5.1 @@ -51,45 +51,45 @@ importers: specifier: ^3.0.2 version: 3.0.2 preact: - specifier: ^10.29.0 - version: 10.29.0 + specifier: ^10.29.1 + version: 10.29.1 react: - specifier: ^19.2.4 - version: 19.2.4 + specifier: ^19.2.5 + version: 19.2.5 react-dom: - specifier: ^19.2.4 - version: 19.2.4(react@19.2.4) + specifier: ^19.2.5 + version: 19.2.5(react@19.2.5) react-icons: specifier: ^5.6.0 - version: 5.6.0(react@19.2.4) + version: 5.6.0(react@19.2.5) react-router: - specifier: ^7.13.1 - version: 7.13.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^7.14.1 + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-toastify: specifier: ^11.0.5 - version: 11.0.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 11.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) typesafe-i18n: specifier: ^5.27.1 - version: 5.27.1(typescript@5.9.3) + version: 5.27.1(typescript@6.0.2) typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.2 + version: 6.0.2 devDependencies: '@babel/core': specifier: ^7.29.0 version: 7.29.0 '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.0.3) + version: 10.0.1(eslint@10.2.0) '@preact/preset-vite': - specifier: ^2.10.4 - version: 2.10.4(@babel/core@7.29.0)(preact@10.29.0)(rollup@4.59.0)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + specifier: ^2.10.5 + version: 2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)) '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.2 - version: 6.0.2(prettier@3.8.1) + version: 6.0.2(prettier@3.8.3) '@types/node': - specifier: ^25.5.0 - version: 25.5.0 + specifier: ^25.6.0 + version: 25.6.0 '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -97,38 +97,38 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) axe-core: - specifier: ^4.11.1 - version: 4.11.1 + specifier: ^4.11.3 + version: 4.11.3 concurrently: specifier: ^9.2.1 version: 9.2.1 eslint: - specifier: ^10.0.3 - version: 10.0.3 + specifier: ^10.2.0 + version: 10.2.0 eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.3) + version: 10.1.8(eslint@10.2.0) prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.3 + version: 3.8.3 rollup-plugin-visualizer: specifier: ^7.0.1 - version: 7.0.1(rolldown@1.0.0-rc.9)(rollup@4.59.0) + version: 7.0.1(rolldown@1.0.0-rc.15)(rollup@4.59.0) terser: specifier: ^5.46.1 version: 5.46.1 typescript-eslint: - specifier: ^8.57.1 - version: 8.57.1(eslint@10.0.3)(typescript@5.9.3) + specifier: ^8.58.2 + version: 8.58.2(eslint@10.2.0)(typescript@6.0.2) vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + specifier: ^8.0.8 + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) vite-plugin-imagemin: specifier: ^0.6.1 - version: 0.6.1(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + version: 0.6.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)) vite-tsconfig-paths: specifier: ^6.1.1 - version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + version: 6.1.1(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)) packages: @@ -237,14 +237,14 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -472,16 +472,16 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.23.3': - resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.3': - resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==} + '@eslint/config-helpers@0.5.5': + resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.1.1': - resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -493,12 +493,12 @@ packages: eslint: optional: true - '@eslint/object-schema@3.0.3': - resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.6.1': - resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} + '@eslint/plugin-kit@0.7.1': + resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@humanfs/core@0.19.1': @@ -536,27 +536,27 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@mui/core-downloads-tracker@7.3.9': - resolution: {integrity: sha512-MOkOCTfbMJwLshlBCKJ59V2F/uaLYfmKnN76kksj6jlGUVdI25A9Hzs08m+zjBRdLv+sK7Rqdsefe8X7h/6PCw==} + '@mui/core-downloads-tracker@9.0.0': + resolution: {integrity: sha512-uwQNGkhv0lf7ufxw6QXev77BW6pWbW+7uxYjU5+rfp4lBkFtMEgJCsarTM3Tn+i0lGx6+Ol2u88JdGXr0GDskA==} - '@mui/icons-material@7.3.9': - resolution: {integrity: sha512-BT+zPJXss8Hg/oEMRmHl17Q97bPACG4ufFSfGEdhiE96jOyR5Dz1ty7ZWt1fVGR0y1p+sSgEwQT/MNZQmoWDCw==} + '@mui/icons-material@9.0.0': + resolution: {integrity: sha512-oDwyvI6LgjWRC9MBcSGvLkPud9S9ELgSBQFYxa1rYcZn6Br55dn22SyvsPDMsn0G8OndFk53iMT45W5mNqrogw==} engines: {node: '>=14.0.0'} peerDependencies: - '@mui/material': ^7.3.9 + '@mui/material': ^9.0.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - '@mui/material@7.3.9': - resolution: {integrity: sha512-I8yO3t4T0y7bvDiR1qhIN6iBWZOTBfVOnmLlM7K6h3dx5YX2a7rnkuXzc2UkZaqhxY9NgTnEbdPlokR1RxCNRQ==} + '@mui/material@9.0.0': + resolution: {integrity: sha512-+VP/oQCDhDR87NQQgXnNBG8dwy6GNuQLnenS1pZvkbn2dKFSxRSRMybTpH9xUxXP+316mlYDy5CSbYtusnCWtw==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 - '@mui/material-pigment-css': ^7.3.9 + '@mui/material-pigment-css': ^9.0.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -570,8 +570,8 @@ packages: '@types/react': optional: true - '@mui/private-theming@7.3.9': - resolution: {integrity: sha512-ErIyRQvsiQEq7Yvcvfw9UDHngaqjMy9P3JDPnRAaKG5qhpl2C4tX/W1S4zJvpu+feihmZJStjIyvnv6KDbIrlw==} + '@mui/private-theming@9.0.0': + resolution: {integrity: sha512-JtuZoaiCqwD6vjgYu6Xp3T7DZkrxJlgtDz5yESzhI34fEX5hHMh2VJUbuL9UOg8xrfIFMrq6dcYoH/7Zi4G0RA==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -580,8 +580,8 @@ packages: '@types/react': optional: true - '@mui/styled-engine@7.3.9': - resolution: {integrity: sha512-JqujWt5bX4okjUPGpVof/7pvgClqh7HvIbsIBIOOlCh2u3wG/Bwp4+E1bc1dXSwkrkp9WUAoNdI5HEC+5HKvMw==} + '@mui/styled-engine@9.0.0': + resolution: {integrity: sha512-9RLGdX4Jg0aQPRuvqh/OLzYSPlgd5zyEw5/1HIRfdavSiOd03WtUaGZH9/w1RoTYuRKwpgy0hpIFaMHIqPVIWg==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.4.1 @@ -593,8 +593,8 @@ packages: '@emotion/styled': optional: true - '@mui/system@7.3.9': - resolution: {integrity: sha512-aL1q9am8XpRrSabv9qWf5RHhJICJql34wnrc1nz0MuOglPRYF/liN+c8VqZdTvUn9qg+ZjRVbKf4sJVFfIDtmg==} + '@mui/system@9.0.0': + resolution: {integrity: sha512-YnC5Zg6j04IxiLc/boAKs0464jfZlLFVa7mf5E8lF0XOtZVUvG6R6gJK50lgUYdaaLdyLfxF6xR7LaPuEpeT/g==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -609,16 +609,16 @@ packages: '@types/react': optional: true - '@mui/types@7.4.12': - resolution: {integrity: sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==} + '@mui/types@9.0.0': + resolution: {integrity: sha512-i1cuFCAWN44b3AJWO7mh7tuh1sqbQSeVr/94oG0TX5uXivac8XalgE4/6fQZcmGZigzbQ35IXxj/4jLpRIBYZg==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - '@mui/utils@7.3.9': - resolution: {integrity: sha512-U6SdZaGbfb65fqTsH3V5oJdFj9uYwyLE2WVuNvmbggTSDBb8QHrFsqY8BN3taK9t3yJ8/BPHD/kNvLNyjwM7Yw==} + '@mui/utils@9.0.0': + resolution: {integrity: sha512-bQcqyg/gjULUqTuyUjSAFr6LQGLvtkNtDbJerAtoUn9kGZ0hg5QJiN1PLHMLbeFpe3te1831uq7GFl2ITokGdg==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -627,8 +627,11 @@ packages: '@types/react': optional: true - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} @@ -646,8 +649,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/types@0.115.0': - resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==} + '@oxc-project/types@0.124.0': + resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -660,8 +663,8 @@ packages: peerDependencies: preact: '*' - '@preact/preset-vite@2.10.4': - resolution: {integrity: sha512-L7RQRs2GiG0lLUz7JSg07vU6lhlzdIthH0eqYZmRR70tTB9ikKCq2LHr+PZzhzIOco3Dioi6P6e/fjAmDUMJbQ==} + '@preact/preset-vite@2.10.5': + resolution: {integrity: sha512-p0vJpxiVO7KWWazWny3LUZ+saXyZKWv6Ju0bYMWNJRp2YveufRPgSUB1C4MTqGJfz07EehMgfN+AJNwQy+w6Iw==} peerDependencies: '@babel/core': 7.x vite: 2.x || 3.x || 4.x || 5.x || 6.x || 7.x || 8.x @@ -683,103 +686,103 @@ packages: preact: ^10.4.0 || ^11.0.0-0 vite: '>=2.0.0' - '@rolldown/binding-android-arm64@1.0.0-rc.9': - resolution: {integrity: sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==} + '@rolldown/binding-android-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.9': - resolution: {integrity: sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.9': - resolution: {integrity: sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==} + '@rolldown/binding-darwin-x64@1.0.0-rc.15': + resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.9': - resolution: {integrity: sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': - resolution: {integrity: sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': - resolution: {integrity: sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': - resolution: {integrity: sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': - resolution: {integrity: sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': - resolution: {integrity: sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': - resolution: {integrity: sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': - resolution: {integrity: sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': - resolution: {integrity: sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.9': - resolution: {integrity: sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': - resolution: {integrity: sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': - resolution: {integrity: sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.9': - resolution: {integrity: sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==} + '@rolldown/pluginutils@1.0.0-rc.15': + resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} @@ -1005,8 +1008,8 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -1033,63 +1036,63 @@ packages: '@types/svgo@2.6.4': resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} - '@typescript-eslint/eslint-plugin@8.57.1': - resolution: {integrity: sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==} + '@typescript-eslint/eslint-plugin@8.58.2': + resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.57.1 + '@typescript-eslint/parser': ^8.58.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.57.1': - resolution: {integrity: sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==} + '@typescript-eslint/parser@8.58.2': + resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.57.1': - resolution: {integrity: sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==} + '@typescript-eslint/project-service@8.58.2': + resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.57.1': - resolution: {integrity: sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==} + '@typescript-eslint/scope-manager@8.58.2': + resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.57.1': - resolution: {integrity: sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==} + '@typescript-eslint/tsconfig-utils@8.58.2': + resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.57.1': - resolution: {integrity: sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==} + '@typescript-eslint/type-utils@8.58.2': + resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.57.1': - resolution: {integrity: sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==} + '@typescript-eslint/types@8.58.2': + resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.57.1': - resolution: {integrity: sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==} + '@typescript-eslint/typescript-estree@8.58.2': + resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.57.1': - resolution: {integrity: sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==} + '@typescript-eslint/utils@8.58.2': + resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.57.1': - resolution: {integrity: sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==} + '@typescript-eslint/visitor-keys@8.58.2': + resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -1158,8 +1161,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.11.1: - resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} + axe-core@4.11.3: + resolution: {integrity: sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==} engines: {node: '>=4'} babel-plugin-macros@3.1.0: @@ -1181,8 +1184,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.9: - resolution: {integrity: sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==} + baseline-browser-mapping@2.10.19: + resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==} engines: {node: '>=6.0.0'} hasBin: true @@ -1212,22 +1215,22 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1260,8 +1263,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -1280,8 +1283,8 @@ packages: resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} engines: {node: '>=0.10.0'} - caniuse-lite@1.0.30001780: - resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} + caniuse-lite@1.0.30001788: + resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} caw@2.0.1: resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} @@ -1516,8 +1519,8 @@ packages: duplexer3@0.1.5: resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} - electron-to-chromium@1.5.321: - resolution: {integrity: sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==} + electron-to-chromium@1.5.337: + resolution: {integrity: sha512-15gKW9mRUNP9RdzhedJNypFUxtYWSXohFz2nTLzM272xbRXHws68kNDzyATG3qej+vUj/7Sn9hf5XTDh0XK6/w==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -1710,8 +1713,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.0.3: - resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==} + eslint@10.2.0: + resolution: {integrity: sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -1792,8 +1795,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-xml-parser@4.5.4: - resolution: {integrity: sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ==} + fast-xml-parser@4.5.6: + resolution: {integrity: sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==} hasBin: true fastq@1.20.1: @@ -2380,8 +2383,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} logalot@2.1.0: resolution: {integrity: sha512-Ah4CgdSRfeCJagxQhcVNMi9BfGYyEKLa6d7OA6xSbld/Hg3Cf2QiOa1mDpmG7Ve8LOH6DN3mdttzjQAvWTyVkw==} @@ -2474,8 +2477,8 @@ packages: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} minimatch@3.1.5: @@ -2510,8 +2513,8 @@ packages: node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -2677,12 +2680,12 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pify@2.3.0: @@ -2714,16 +2717,16 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} powershell-utils@0.1.0: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} - preact@10.29.0: - resolution: {integrity: sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==} + preact@10.29.1: + resolution: {integrity: sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -2737,8 +2740,8 @@ packages: resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} engines: {node: '>=4'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true @@ -2771,10 +2774,10 @@ packages: rate-limiter-flexible@5.0.5: resolution: {integrity: sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==} - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-icons@5.6.0: resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} @@ -2784,11 +2787,11 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@19.2.4: - resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==} + react-is@19.2.5: + resolution: {integrity: sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==} - react-router@7.13.1: - resolution: {integrity: sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==} + react-router@7.14.1: + resolution: {integrity: sha512-5BCvFskyAAVumqhEKh/iPhLOIkfxcEUz8WqFIARCkMg8hZZzDYX9CtwxXA0e+qT8zAxmMC0x3Ckb9iMONwc5jg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -2822,8 +2825,8 @@ packages: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} read-pkg-up@1.0.1: @@ -2857,8 +2860,8 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true @@ -2874,8 +2877,8 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rolldown@1.0.0-rc.9: - resolution: {integrity: sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==} + rolldown@1.0.0-rc.15: + resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3139,8 +3142,8 @@ packages: resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} engines: {node: '>=0.10.0'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} to-buffer@1.2.2: @@ -3203,23 +3206,23 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript-eslint@8.57.1: - resolution: {integrity: sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==} + typescript-eslint@8.58.2: + resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} engines: {node: '>=14.17'} hasBin: true unbzip2-stream@1.4.3: resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} @@ -3272,15 +3275,16 @@ packages: peerDependencies: vite: '*' - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.0.8: + resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -3291,12 +3295,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -3358,8 +3364,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} yargs-parser@21.1.1: @@ -3441,7 +3447,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -3528,18 +3534,18 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@emnapi/core@1.9.1': + '@emnapi/core@1.9.2': dependencies: - '@emnapi/wasi-threads': 1.2.0 + '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.1': + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.0': + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 optional: true @@ -3576,17 +3582,17 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)': + '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.5) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: @@ -3602,16 +3608,16 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.5) '@emotion/utils': 1.4.2 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: @@ -3619,9 +3625,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.4)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 '@emotion/utils@1.4.2': {} @@ -3708,38 +3714,38 @@ snapshots: '@esbuild/win32-x64@0.27.4': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.3)': + '@eslint-community/eslint-utils@4.9.1(eslint@10.2.0)': dependencies: - eslint: 10.0.3 + eslint: 10.2.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.3': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 3.0.3 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.3': + '@eslint/config-helpers@0.5.5': dependencies: - '@eslint/core': 1.1.1 + '@eslint/core': 1.2.1 - '@eslint/core@1.1.1': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.0.3)': + '@eslint/js@10.0.1(eslint@10.2.0)': optionalDependencies: - eslint: 10.0.3 + eslint: 10.2.0 - '@eslint/object-schema@3.0.3': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.6.1': + '@eslint/plugin-kit@0.7.1': dependencies: - '@eslint/core': 1.1.1 + '@eslint/core': 1.2.1 levn: 0.4.1 '@humanfs/core@0.19.1': {} @@ -3777,47 +3783,47 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@mui/core-downloads-tracker@7.3.9': {} + '@mui/core-downloads-tracker@9.0.0': {} - '@mui/icons-material@7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@mui/icons-material@9.0.0(@mui/material@9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 + '@mui/material': 9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@mui/material@9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/core-downloads-tracker': 7.3.9 - '@mui/system': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/types': 7.4.12(@types/react@19.2.14) - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/core-downloads-tracker': 9.0.0 + '@mui/system': 9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/types': 9.0.0(@types/react@19.2.14) + '@mui/utils': 9.0.0(@types/react@19.2.14)(react@19.2.5) '@popperjs/core': 2.11.8 '@types/react-transition-group': 4.4.12(@types/react@19.2.14) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-is: 19.2.4 - react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-is: 19.2.5 + react-transition-group: 4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 - '@mui/private-theming@7.3.9(@types/react@19.2.14)(react@19.2.4)': + '@mui/private-theming@9.0.0(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 9.0.0(@types/react@19.2.14)(react@19.2.5) prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@mui/styled-engine@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@mui/styled-engine@9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@emotion/cache': 11.14.0 @@ -3825,49 +3831,49 @@ snapshots: '@emotion/sheet': 1.4.0 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) - '@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@mui/system@9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/private-theming': 7.3.9(@types/react@19.2.14)(react@19.2.4) - '@mui/styled-engine': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - '@mui/types': 7.4.12(@types/react@19.2.14) - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/private-theming': 9.0.0(@types/react@19.2.14)(react@19.2.5) + '@mui/styled-engine': 9.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@mui/types': 9.0.0(@types/react@19.2.14) + '@mui/utils': 9.0.0(@types/react@19.2.14)(react@19.2.5) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 - '@mui/types@7.4.12(@types/react@19.2.14)': + '@mui/types@9.0.0(@types/react@19.2.14)': dependencies: '@babel/runtime': 7.29.2 optionalDependencies: '@types/react': 19.2.14 - '@mui/utils@7.3.9(@types/react@19.2.14)(react@19.2.4)': + '@mui/utils@9.0.0(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/types': 7.4.12(@types/react@19.2.14) + '@mui/types': 9.0.0(@types/react@19.2.14) '@types/prop-types': 15.7.15 clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.4 - react-is: 19.2.4 + react: 19.2.5 + react-is: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@napi-rs/wasm-runtime@1.1.1': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 '@tybys/wasm-util': 0.10.1 optional: true @@ -3885,8 +3891,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oxc-project/types@0.115.0': - optional: true + '@oxc-project/types@0.124.0': {} '@paralleldrive/cuid2@2.3.1': dependencies: @@ -3894,23 +3899,23 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/compat@18.3.2(preact@10.29.0)': + '@preact/compat@18.3.2(preact@10.29.1)': dependencies: - preact: 10.29.0 + preact: 10.29.1 - '@preact/preset-vite@2.10.4(@babel/core@7.29.0)(preact@10.29.0)(rollup@4.59.0)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1))': + '@preact/preset-vite@2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) - '@prefresh/vite': 2.4.12(preact@10.29.0)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + '@prefresh/vite': 2.4.12(preact@10.29.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)) '@rollup/pluginutils': 5.3.0(rollup@4.59.0) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0) debug: 4.4.3 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) - vite-prerender-plugin: 0.5.13(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) + vite-prerender-plugin: 0.5.13(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)) zimmerframe: 1.1.4 transitivePeerDependencies: - preact @@ -3919,84 +3924,85 @@ snapshots: '@prefresh/babel-plugin@0.5.3': {} - '@prefresh/core@1.5.9(preact@10.29.0)': + '@prefresh/core@1.5.9(preact@10.29.1)': dependencies: - preact: 10.29.0 + preact: 10.29.1 '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.12(preact@10.29.0)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1))': + '@prefresh/vite@2.4.12(preact@10.29.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))': dependencies: '@babel/core': 7.29.0 '@prefresh/babel-plugin': 0.5.3 - '@prefresh/core': 1.5.9(preact@10.29.0) + '@prefresh/core': 1.5.9(preact@10.29.1) '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 - preact: 10.29.0 - vite: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + preact: 10.29.1 + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) transitivePeerDependencies: - supports-color - '@rolldown/binding-android-arm64@1.0.0-rc.9': + '@rolldown/binding-android-arm64@1.0.0-rc.15': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.9': + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.9': + '@rolldown/binding-darwin-x64@1.0.0-rc.15': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.9': + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.9': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': optional: true - '@rolldown/pluginutils@1.0.0-rc.9': - optional: true + '@rolldown/pluginutils@1.0.0-rc.15': {} '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 - picomatch: 2.3.1 + picomatch: 2.3.2 '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: rollup: 4.59.0 @@ -4077,26 +4083,26 @@ snapshots: '@sindresorhus/is@0.7.0': {} - '@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) clsx: 1.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react-window: 1.8.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-window: 1.8.11(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)': + '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)': dependencies: '@babel/generator': 7.29.1 '@babel/parser': 7.29.2 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 javascript-natural-sort: 0.7.1 - lodash-es: 4.17.23 + lodash-es: 4.18.1 minimatch: 9.0.9 parse-imports-exports: 0.2.4 - prettier: 3.8.1 + prettier: 3.8.3 transitivePeerDependencies: - supports-color @@ -4112,7 +4118,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/imagemin-gifsicle@7.0.4': dependencies: @@ -4141,21 +4147,21 @@ snapshots: '@types/imagemin@7.0.1': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/json-schema@7.0.15': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/minimatch@6.0.0': dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 - '@types/node@25.5.0': + '@types/node@25.6.0': dependencies: - undici-types: 7.18.2 + undici-types: 7.19.2 '@types/parse-json@4.0.2': {} @@ -4175,101 +4181,101 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/svgo@2.6.4': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 - '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.1(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 - eslint: 10.0.3 + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 + eslint: 10.2.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.2) + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.1(eslint@10.0.3)(typescript@5.9.3)': + '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 - eslint: 10.0.3 - typescript: 5.9.3 + eslint: 10.2.0 + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 debug: 4.4.3 - typescript: 5.9.3 + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.57.1': + '@typescript-eslint/scope-manager@8.58.2': dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/visitor-keys': 8.57.1 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 - '@typescript-eslint/tsconfig-utils@8.57.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)': dependencies: - typescript: 5.9.3 + typescript: 6.0.2 - '@typescript-eslint/type-utils@8.57.1(eslint@10.0.3)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) debug: 4.4.3 - eslint: 10.0.3 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + eslint: 10.2.0 + ts-api-utils: 2.5.0(typescript@6.0.2) + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.57.1': {} + '@typescript-eslint/types@8.58.2': {} - '@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/project-service': 8.57.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/visitor-keys': 8.57.1 + '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2) + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.5 semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@6.0.2) + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.1(eslint@10.0.3)(typescript@5.9.3)': + '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - eslint: 10.0.3 - typescript: 5.9.3 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + eslint: 10.2.0 + typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.57.1': + '@typescript-eslint/visitor-keys@8.58.2': dependencies: - '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/types': 8.58.2 eslint-visitor-keys: 5.0.1 acorn-jsx@5.3.2(acorn@8.16.0): @@ -4322,13 +4328,13 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.11.1: {} + axe-core@4.11.3: {} babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.29.2 cosmiconfig: 7.1.0 - resolve: 1.22.11 + resolve: 1.22.12 babel-plugin-transform-hook-names@1.0.2(@babel/core@7.29.0): dependencies: @@ -4340,7 +4346,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.9: {} + baseline-browser-mapping@2.10.19: {} bin-build@3.0.0: dependencies: @@ -4382,16 +4388,16 @@ snapshots: boolbase@1.0.0: {} - brace-expansion@1.1.12: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -4399,13 +4405,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.9 - caniuse-lite: 1.0.30001780 - electron-to-chromium: 1.5.321 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.10.19 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.337 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-alloc-unsafe@1.1.0: {} @@ -4444,7 +4450,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -4465,7 +4471,7 @@ snapshots: camelcase@2.1.1: {} - caniuse-lite@1.0.30001780: {} + caniuse-lite@1.0.30001788: {} caw@2.0.1: dependencies: @@ -4553,7 +4559,7 @@ snapshots: import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 - yaml: 1.10.2 + yaml: 1.10.3 cross-spawn@5.1.0: dependencies: @@ -4680,8 +4686,7 @@ snapshots: define-lazy-prop@3.0.0: {} - detect-libc@2.1.2: - optional: true + detect-libc@2.1.2: {} dezalgo@1.0.4: dependencies: @@ -4768,7 +4773,7 @@ snapshots: duplexer3@0.1.5: {} - electron-to-chromium@1.5.321: {} + electron-to-chromium@1.5.337: {} emoji-regex@10.6.0: {} @@ -4906,6 +4911,7 @@ snapshots: '@esbuild/win32-arm64': 0.27.4 '@esbuild/win32-ia32': 0.27.4 '@esbuild/win32-x64': 0.27.4 + optional: true escalade@3.2.0: {} @@ -4913,9 +4919,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.0.3): + eslint-config-prettier@10.1.8(eslint@10.2.0): dependencies: - eslint: 10.0.3 + eslint: 10.2.0 eslint-scope@9.1.2: dependencies: @@ -4928,14 +4934,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.0.3: + eslint@10.2.0: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.3 - '@eslint/config-helpers': 0.5.3 - '@eslint/core': 1.1.1 - '@eslint/plugin-kit': 0.6.1 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.5.5 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -4957,7 +4963,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 transitivePeerDependencies: @@ -5064,7 +5070,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-xml-parser@4.5.4: + fast-xml-parser@4.5.6: dependencies: strnum: 1.1.2 @@ -5076,9 +5082,9 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 figures@1.7.0: dependencies: @@ -5477,7 +5483,7 @@ snapshots: is-svg@4.4.0: dependencies: - fast-xml-parser: 4.5.4 + fast-xml-parser: 4.5.6 is-typed-array@1.1.15: dependencies: @@ -5602,7 +5608,6 @@ snapshots: lightningcss-linux-x64-musl: 1.32.0 lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - optional: true lines-and-columns@1.2.4: {} @@ -5618,7 +5623,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.23: {} + lodash-es@4.18.1: {} logalot@2.1.0: dependencies: @@ -5696,7 +5701,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.54.0: {} @@ -5708,17 +5713,17 @@ snapshots: mimic-response@1.0.1: {} - minimatch@10.2.4: + minimatch@10.2.5: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.5 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.14 minimatch@9.0.9: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.0 minimist@1.2.8: {} @@ -5740,12 +5745,12 @@ snapshots: css-select: 5.2.2 he: 1.2.0 - node-releases@2.0.36: {} + node-releases@2.0.37: {} normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.11 + resolve: 1.22.12 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -5902,9 +5907,9 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} pify@2.3.0: {} @@ -5926,7 +5931,7 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss@8.5.8: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -5934,7 +5939,7 @@ snapshots: powershell-utils@0.1.0: {} - preact@10.29.0: {} + preact@10.29.1: {} prelude-ls@1.2.1: {} @@ -5942,7 +5947,7 @@ snapshots: prepend-http@2.0.0: {} - prettier@3.8.1: {} + prettier@3.8.3: {} process-nextick-args@2.0.1: {} @@ -5973,55 +5978,55 @@ snapshots: rate-limiter-flexible@5.0.5: {} - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 - react-icons@5.6.0(react@19.2.4): + react-icons@5.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 react-is@16.13.1: {} - react-is@19.2.4: {} + react-is@19.2.5: {} - react-router@7.13.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: cookie: 1.1.1 - react: 19.2.4 + react: 19.2.5 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) - react-toastify@11.0.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-toastify@11.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: clsx: 2.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react-transition-group@4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-transition-group@4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@babel/runtime': 7.29.2 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react-virtualized-auto-sizer@1.0.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-virtualized-auto-sizer@1.0.26(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react-window@1.8.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-window@1.8.11(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@babel/runtime': 7.29.2 memoize-one: 5.2.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react@19.2.4: {} + react@19.2.5: {} read-pkg-up@1.0.1: dependencies: @@ -6059,8 +6064,9 @@ snapshots: resolve-from@4.0.0: {} - resolve@1.22.11: + resolve@1.22.12: dependencies: + es-errors: 1.3.0 is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -6075,36 +6081,35 @@ snapshots: dependencies: glob: 7.2.3 - rolldown@1.0.0-rc.9: + rolldown@1.0.0-rc.15: dependencies: - '@oxc-project/types': 0.115.0 - '@rolldown/pluginutils': 1.0.0-rc.9 + '@oxc-project/types': 0.124.0 + '@rolldown/pluginutils': 1.0.0-rc.15 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.9 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.9 - '@rolldown/binding-darwin-x64': 1.0.0-rc.9 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.9 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.9 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.9 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.9 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.9 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.9 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.9 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.9 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.9 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.9 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.9 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.9 - optional: true + '@rolldown/binding-android-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-x64': 1.0.0-rc.15 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 - rollup-plugin-visualizer@7.0.1(rolldown@1.0.0-rc.9)(rollup@4.59.0): + rollup-plugin-visualizer@7.0.1(rolldown@1.0.0-rc.15)(rollup@4.59.0): dependencies: open: 11.0.0 - picomatch: 4.0.3 + picomatch: 4.0.4 source-map: 0.7.6 yargs: 18.0.0 optionalDependencies: - rolldown: 1.0.0-rc.9 + rolldown: 1.0.0-rc.15 rollup: 4.59.0 rollup@4.59.0: @@ -6137,6 +6142,7 @@ snapshots: '@rollup/rollup-win32-x64-gnu': 4.59.0 '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + optional: true run-applescript@7.1.0: {} @@ -6358,10 +6364,10 @@ snapshots: timed-out@4.0.1: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 to-buffer@1.2.2: dependencies: @@ -6381,13 +6387,13 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - ts-api-utils@2.5.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@6.0.2): dependencies: - typescript: 5.9.3 + typescript: 6.0.2 - tsconfck@3.1.6(typescript@5.9.3): + tsconfck@3.1.6(typescript@6.0.2): optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.2 tslib@2.8.1: {} @@ -6407,35 +6413,35 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.15 - typesafe-i18n@5.27.1(typescript@5.9.3): + typesafe-i18n@5.27.1(typescript@6.0.2): dependencies: - typescript: 5.9.3 + typescript: 6.0.2 - typescript-eslint@8.57.1(eslint@10.0.3)(typescript@5.9.3): + typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.1(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.0.3)(typescript@5.9.3) - eslint: 10.0.3 - typescript: 5.9.3 + '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + eslint: 10.2.0 + typescript: 6.0.2 transitivePeerDependencies: - supports-color - typescript@5.9.3: {} + typescript@6.0.2: {} unbzip2-stream@1.4.3: dependencies: buffer: 5.7.1 through: 2.3.8 - undici-types@7.18.2: {} + undici-types@7.19.2: {} universalify@2.0.1: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -6462,7 +6468,7 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-plugin-imagemin@0.6.1(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)): + vite-plugin-imagemin@0.6.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)): dependencies: '@types/imagemin': 7.0.1 '@types/imagemin-gifsicle': 7.0.4 @@ -6487,11 +6493,11 @@ snapshots: imagemin-webp: 6.1.0 jpegtran-bin: 6.0.1 pathe: 0.2.0 - vite: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) transitivePeerDependencies: - supports-color - vite-prerender-plugin@0.5.13(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)): + vite-prerender-plugin@0.5.13(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)): dependencies: kolorist: 1.8.0 magic-string: 0.30.21 @@ -6499,36 +6505,35 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.6 stack-trace: 1.0.0-pre2 - vite: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) - vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)): + vite-tsconfig-paths@6.1.1(typescript@6.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.9.3) - vite: 7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + tsconfck: 3.1.6(typescript@6.0.2) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) transitivePeerDependencies: - supports-color - typescript - vite@7.3.1(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1): + vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1): dependencies: - esbuild: 0.27.4 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.8 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.5.0 - fsevents: 2.3.3 lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.10 + rolldown: 1.0.0-rc.15 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.6.0 + esbuild: 0.27.4 + fsevents: 2.3.3 terser: 5.46.1 which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 @@ -6572,7 +6577,7 @@ snapshots: yallist@3.1.1: {} - yaml@1.10.2: {} + yaml@1.10.3: {} yargs-parser@21.1.1: {} diff --git a/interface/src/SignIn.tsx b/interface/src/SignIn.tsx index c113fff17..7b26d94dc 100644 --- a/interface/src/SignIn.tsx +++ b/interface/src/SignIn.tsx @@ -3,6 +3,7 @@ import { toast } from 'react-toastify'; import ForwardIcon from '@mui/icons-material/Forward'; import { Box, Button, Paper, Typography } from '@mui/material'; +import type { Theme } from '@mui/material/styles'; import * as AuthenticationApi from 'components/routing/authentication'; import { useRequest } from 'alova/client'; @@ -36,7 +37,7 @@ const SignIn = memo(() => { { immediate: false } - ).onSuccess((response) => { + ).onSuccess((response: { data: { access_token: string } }) => { if (response.data) { authenticationContext.signIn(response.data.access_token); } @@ -78,7 +79,6 @@ const SignIn = memo(() => { } }, [signInRequest, signIn, LL]); - // Memoize callback to prevent recreation on every render const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]); // get rid of scrollbar @@ -92,13 +92,15 @@ const SignIn = memo(() => { return ( theme.breakpoints.values.sm} + sx={(theme: Theme) => ({ + display: 'flex', + height: '100vh', + margin: 'auto', + padding: 2, + justifyContent: 'center', + flexDirection: 'column', + maxWidth: theme.breakpoints.values.sm + })} > ({ @@ -111,16 +113,18 @@ const SignIn = memo(() => { width: '100%' })} > - + {PROJECT_NAME} { return ( {blocker ? : null} - - {LL.ENTITIES_HELP_1()}. - + + {LL.ENTITIES_HELP_1()}. + {renderEntity()} @@ -361,8 +361,8 @@ const CustomEntities = () => { /> )} - - + + {numChanges > 0 && ( ) : ( - - + + {numChanges !== 0 && ( - + - + ©  { return ( <> - - {LL.MODULES_DESCRIPTION()}. - + + {LL.MODULES_DESCRIPTION()}. + { )}
- - + + {numChanges !== 0 && ( + + + + ), + [confirmBackup, handleCloseBackupDialog, LL] ); const handleDownload = useCallback( @@ -118,58 +128,57 @@ const DownloadUpload = () => { ); } - const gridButtons = downloadButtons.filter((btn) => btn.isGridButton); - const standaloneButton = downloadButtons.find((btn) => !btn.isGridButton); - return ( + {renderBackupDialog} + {LL.DOWNLOAD(0)} - - {LL.DOWNLOAD_SETTINGS_TEXT()}. - - - - {gridButtons.map((button) => ( - - - - ))} - - - - {LL.DOWNLOAD_SETTINGS_TEXT2()}. - - - {standaloneButton && ( + + + {LL.DOWNLOAD_SETTINGS_TEXT()}: + - )} + + + + + {LL.DOWNLOAD_SETTINGS_TEXT2()}: + + + {LL.UPLOAD()} - - {LL.UPLOAD_TEXT()}. - + + {LL.UPLOAD_TEXT()}: + - + ); }; diff --git a/interface/src/app/settings/MqttSettings.tsx b/interface/src/app/settings/MqttSettings.tsx index f910cadcd..a2ae1c236 100644 --- a/interface/src/app/settings/MqttSettings.tsx +++ b/interface/src/app/settings/MqttSettings.tsx @@ -129,7 +129,7 @@ const MqttSettings = () => { {blocker ? : null} <> - + { {timeZoneItems}
- + {!data.enabled && !dirtyFlags.length && ( - + @@ -371,7 +399,9 @@ const InstallPartitionDialog = memo( {LL.INSTALL()} {LL.STORED_VERSIONS()} - {LL.INSTALL_VERSION(LL.INSTALL(), version)} + + {LL.INSTALL_VERSION(LL.INSTALL(), version)} + + {showUpgradeDialog && upgradeImportantMessageType > 0 && ( + setShowUpgradeDialog(false)} + > + + +    + {LL.UPGRADE_IMPORTANT_MESSAGES()} + + + {upgradeImportantMessageType === 2 && + LL.UPGRADE_IMPORTANT_MESSAGES_2()} + {upgradeImportantMessageType === 1 && ( + <> + {LL.UPGRADE_IMPORTANT_MESSAGES_1()} + + + {LL.DOWNLOAD_SYSTEM_BACKUP()} + + + + )}{' '} + + + {LL.ONLINE_HELP()} + + + + + + + + + )} )} diff --git a/interface/src/components/upload/SingleUpload.tsx b/interface/src/components/upload/SingleUpload.tsx index 5ad6941f2..0363cd445 100644 --- a/interface/src/components/upload/SingleUpload.tsx +++ b/interface/src/components/upload/SingleUpload.tsx @@ -13,11 +13,10 @@ import DragNdrop from './DragNdrop'; import { LinearProgressWithLabel } from './LinearProgressWithLabel'; interface SingleUploadProps { - text: string; doRestart: () => void; } -const SingleUpload = ({ text, doRestart }: SingleUploadProps) => { +const SingleUpload = ({ doRestart }: SingleUploadProps) => { const [md5, setMd5] = useState(); const [file, setFile] = useState(); const { LL } = useI18nContext(); @@ -58,7 +57,7 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => { <> {isUploading ? ( <> - + { ) : ( - + )} {md5 && ( - + {'MD5: ' + md5} )} diff --git a/interface/src/i18n/cz/index.ts b/interface/src/i18n/cz/index.ts index 27cef9a70..9bc067dfb 100644 --- a/interface/src/i18n/cz/index.ts +++ b/interface/src/i18n/cz/index.ts @@ -186,7 +186,8 @@ const cz: Translation = { BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti', COMPACT: 'Kompaktní', DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace', - DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechna data', + DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty', + DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)', UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr', ERROR: 'Neočekávaná chyba, zkuste to prosím znovu', @@ -357,7 +358,13 @@ const cz: Translation = { FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', NO_DATA: 'Žádná data', USER_PROFILE: 'Uživatelský profil', - STORED_VERSIONS: 'Uložené verze' + STORED_VERSIONS: 'Uložené verze', + ONLINE_HELP: 'online nápověda', + UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovat důležité zprávy', + UPGRADE_IMPORTANT_MESSAGES_1: 'Tato aktualizace vyžaduje obnovení továrního nastavení. Ujistěte se, že jste vytvořili zálohu své konfigurace a nastavení před pokračováním a nahrajte ji po instalaci nové verze.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete se na novou hlavní verzi. Ujistěte se, že jste přečetli ChangeLog pro jakékoliv závažné změny.', + WARNING_SYSTEM_BACKUP: 'Toto vytvoří zálohu vašich celých systémových konfigurací a nastavení. Všechna hesla budou v zálohovém souboru čitelná. Buďte opatrní při sdílení! Opravdu chcete pokračovat?' + }; export default cz; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 53634bde9..12c1e6ed7 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -186,7 +186,8 @@ const de: Translation = { BUFFER_SIZE: 'Max. Puffergröße', COMPACT: 'Kompakte Darstellung', DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen', - DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Daten', + DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte', + DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung', UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch', UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier', ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.', @@ -357,7 +358,13 @@ const de: Translation = { FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation', NO_DATA: 'Keine Daten', USER_PROFILE: 'Benutzerprofil', - STORED_VERSIONS: 'Gespeicherte Versionen' + STORED_VERSIONS: 'Gespeicherte Versionen', + ONLINE_HELP: 'Online-Hilfe', + UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten aktualisieren', + UPGRADE_IMPORTANT_MESSAGES_1: 'Diese Aktualisierung erfordert eine Werkseinstellung. Stellen Sie sicher, dass Sie eine Sicherung Ihrer Konfiguration und Einstellungen vor dem Fortfahren erstellt haben und diese nach der Installation der neuen Version hochladen.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Sie aktualisieren auf eine neue Hauptversion. Stellen Sie sicher, dass Sie den ChangeLog für alle wichtigen Änderungen gelesen haben.', + WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und -einstellungen erstellen. Alle Passwörter werden im Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?' + }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 7196fcd6e..8c8f8dcbd 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -186,7 +186,8 @@ const en: Translation = { BUFFER_SIZE: 'Max Buffer Size', COMPACT: 'Compact', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', - DOWNLOAD_SETTINGS_TEXT2: 'Export all data', + DOWNLOAD_SETTINGS_TEXT2: 'Export all values', + DOWNLOAD_SYSTEM_BACKUP: 'System Backup', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', ERROR: 'Unexpected Error, please try again', @@ -357,7 +358,13 @@ const en: Translation = { FIRMWARE_VERSION_INFO: 'Firmware Version Information', NO_DATA: 'No data', USER_PROFILE: 'User Profile', - STORED_VERSIONS: 'Stored Versions' + STORED_VERSIONS: 'Stored Versions', + ONLINE_HELP: 'online help', + UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Important Messages', + UPGRADE_IMPORTANT_MESSAGES_1: 'This upgrade requires a factory reset. Make sure you have made a backup of your configuration and settings before continuing, and upload this after the new version is installed.', + UPGRADE_IMPORTANT_MESSAGES_2: 'You are upgrading to a new major version. Make sure you have read the ChangeLog for any breaking changes.', + WARNING_SYSTEM_BACKUP: 'This will create a backup of your full system configuration and settings. All passwords will be readable in the backup file. Be careful with sharing! Do you want to continue?' + }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 13a18327a..e576a5950 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -186,7 +186,8 @@ const fr: Translation = { BUFFER_SIZE: 'Max taille du buffer', COMPACT: 'Compact', DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations', - DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les données', + DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs', + DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système', UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', ERROR: 'Erreur inattendue, veuillez réessayer', @@ -357,7 +358,13 @@ const fr: Translation = { FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware', NO_DATA: 'Aucune donnée', USER_PROFILE: 'Profil utilisateur', - STORED_VERSIONS: 'Versions stockées' + STORED_VERSIONS: 'Versions stockées', + ONLINE_HELP: 'aide en ligne', + UPGRADE_IMPORTANT_MESSAGES: 'Mettre à jour les messages importants', + UPGRADE_IMPORTANT_MESSAGES_1: 'Cette mise à jour nécessite une réinitialisation de fabrique. Assurez-vous d\'avoir créé une sauvegarde de vos configurations et paramètres avant de continuer et de la charger après l\'installation de la nouvelle version.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Vous mettez à jour vers une nouvelle version majeure. Assurez-vous de lire le ChangeLog pour tout changement important.', + WARNING_SYSTEM_BACKUP: 'Cela créera une sauvegarde de votre configuration et paramètres complets. Tous les mots de passe seront lisibles dans le fichier de sauvegarde. Soyez prudent avec le partage ! Voulez-vous continuer ?' + }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 51f29f9fe..4e86cbc03 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -186,7 +186,8 @@ const it: Translation = { BUFFER_SIZE: 'Max Buffer Size', COMPACT: 'Compatto', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', - DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i dati', + DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori', + DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', ERROR: 'Errore Inaspettato, prego tenta ancora', @@ -357,7 +358,13 @@ const it: Translation = { FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware', NO_DATA: 'Nessun dato', USER_PROFILE: 'Profilo utente', - STORED_VERSIONS: 'Versioni memorizzate' + STORED_VERSIONS: 'Versioni memorizzate', + ONLINE_HELP: 'aiuto online', + UPGRADE_IMPORTANT_MESSAGES: 'Aggiorna Messaggi Importanti', + UPGRADE_IMPORTANT_MESSAGES_1: 'Questa aggiornamento richiede un ripristino di fabbrica. Assicurati di aver creato un backup delle tue configurazioni e impostazioni prima di continuare e di caricarlo dopo l\'installazione della nuova versione.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Stai aggiornando a una nuova versione principale. Assicurati di aver letto il ChangeLog per qualsiasi cambiamento importante.', + WARNING_SYSTEM_BACKUP: 'Questo creerà un backup delle tue configurazioni e impostazioni complete. Tutte le password saranno leggibili nel file di backup. Sei sicuro di voler continuare?' + }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index bd0d0e6f7..f246aa684 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -186,7 +186,8 @@ const nl: Translation = { BUFFER_SIZE: 'Max buffer grootte', COMPACT: 'Compact', DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen', - DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle data', + DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden', + DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup', UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)', UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier', ERROR: 'Onverwachte fout, probeer opnieuw', @@ -357,7 +358,13 @@ const nl: Translation = { FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie', NO_DATA: 'Geen data', USER_PROFILE: 'Gebruikersprofiel', - STORED_VERSIONS: 'Opgeslagen versies' + STORED_VERSIONS: 'Opgeslagen versies', + ONLINE_HELP: 'online help', + UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Belangrijke Berichten', + UPGRADE_IMPORTANT_MESSAGES_1: 'Deze upgrade vereist een fabrieksinstelling. Zorg ervoor dat u een back-up van uw configuratie en instellingen hebt gemaakt voordat u doorgaat en upload deze na de installatie van de nieuwe versie.', + UPGRADE_IMPORTANT_MESSAGES_2: 'U updatet naar een nieuwe grote versie. Zorg ervoor dat u de ChangeLog hebt gelezen voor alle brekende wijzigingen.', + WARNING_SYSTEM_BACKUP: 'Dit zal een back-up van uw volledige systeemconfiguratie en instellingen maken. Alle wachtwoorden zijn leesbaar in het back-upbestand. Wees voorzichtig bij delen! Wilt u doorgaan?' + }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 63365268d..84f56b6ae 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -186,7 +186,8 @@ const no: Translation = { BUFFER_SIZE: 'Max Buffer Størrelse', COMPACT: 'Komprimere', DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger', - DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle data', + DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier', + DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi', UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)', UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her', ERROR: 'Ukjent feil, prøv igjen', @@ -357,7 +358,13 @@ const no: Translation = { FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon', NO_DATA: 'Ingen data', USER_PROFILE: 'Brukerprofil', - STORED_VERSIONS: 'Lagret versjoner' + STORED_VERSIONS: 'Lagret versjoner', + ONLINE_HELP: 'online hjelp', + UPGRADE_IMPORTANT_MESSAGES: 'Oppdater viktige meldinger', + UPGRADE_IMPORTANT_MESSAGES_1: 'Denne oppdateringen krever en fabriksinstilling. Sørg for at du har laget en sikkerhetskopi av din konfigurasjon og innstillinger før du fortsetter, og last denne opp etter at den nye versjonen er installert.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Du oppdaterer til en ny hovedversjon. Sørg for at du har lest ChangeLog for eventuelle bruddende endringer.', + WARNING_SYSTEM_BACKUP: 'Dette vil lage en sikkerhetskopi av din fullstendige systemkonfigurasjon og innstillinger. Alle passord vil være lesbare i sikkerhetskopien. Vær forsiktig med deling! Vil du fortsette?' + }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 60ee8b58f..da445c469 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -186,7 +186,8 @@ const pl: BaseTranslation = { BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)', COMPACT: 'Kompaktowy', DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji', - DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie dane', + DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości', + DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu', UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)', UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', @@ -357,7 +358,13 @@ const pl: BaseTranslation = { FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware', NO_DATA: 'Brak danych', USER_PROFILE: 'Profil użytkownika', - STORED_VERSIONS: 'Zapisane wersje' + STORED_VERSIONS: 'Zapisane wersje', + ONLINE_HELP: 'pomoc online', + UPGRADE_IMPORTANT_MESSAGES: 'Aktualizuj ważne wiadomości', + UPGRADE_IMPORTANT_MESSAGES_1: 'Ta aktualizacja wymaga resetu fabrycznego. Upewnij się, że masz utworzoną kopię swoich ustawień i konfiguracji przed kontynuowaniem i przesuń ją po zainstalowaniu nowej wersji.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujesz się do nowej głównej wersji. Upewnij się, że przeczytałeś ChangeLog dla wszelkich istotnych zmian.', + WARNING_SYSTEM_BACKUP: 'To spowoduje utworzenie kopii zapasowej całej konfiguracji i ustawień systemu. Wszystkie hasła będą widoczne w pliku kopii zapasowej. Bądź ostrożny przy udostępnianiu! Chcesz kontynuować?' + }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index 7a4eb526d..0f4697fe0 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -186,7 +186,8 @@ const sk: Translation = { BUFFER_SIZE: 'Buffer-max. veľkosť', COMPACT: 'Kompaktné', DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení', - DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky dáta', + DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty', + DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)', UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem', ERROR: 'Neočakávaná chyba, prosím skúste to znova', @@ -357,7 +358,13 @@ const sk: Translation = { FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware', NO_DATA: 'Žiadne dáta', USER_PROFILE: 'Profil používateľa', - STORED_VERSIONS: 'Uložené verzie' + STORED_VERSIONS: 'Uložené verzie', + ONLINE_HELP: 'online pomoc', + UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovať dôležité správy', + UPGRADE_IMPORTANT_MESSAGES_1: 'Táto aktualizácia vyžaduje reštart základných nastavení. Uistite sa, že ste vytvorili zálohu svojich konfigurácií a nastavení pred pokračovaním a nahrajte ju po instalácii novej verzie.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete sa na novú hlavnú verziu. Uistite sa, že ste prečítali ChangeLog pre akékoľvek dôležité zmeny.', + WARNING_SYSTEM_BACKUP: 'Toto vytvorí zálohu všetkých vašich celých systémových konfigurácií a nastavení. Všetky hesla budú čitateľné v zálohovom súbore. Buďte opatrní pri zdieľaní! Chcete pokračovať?' + }; export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 7ff150a83..3cff59b90 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -186,7 +186,8 @@ const sv: Translation = { BUFFER_SIZE: 'Max bufferstorlek', COMPACT: 'Komprimerad', DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar', - DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla data', + DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden', + DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia', UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)', UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här', ERROR: 'Okänt fel, var god försök igen', @@ -357,7 +358,13 @@ const sv: Translation = { FIRMWARE_VERSION_INFO: 'Information om firmwareversion', NO_DATA: 'Ingen data', USER_PROFILE: 'Användarprofil', - STORED_VERSIONS: 'Lagrad versioner' + STORED_VERSIONS: 'Lagrad versioner', + ONLINE_HELP: 'online hjälp', + UPGRADE_IMPORTANT_MESSAGES: 'Uppdatera viktiga meddelanden', + UPGRADE_IMPORTANT_MESSAGES_1: 'Denna uppdatering kräver en fabriksåterställning. Se till att du har gjort en säkerhetskopia av din konfiguration och inställningar innan du fortsätter och ladda upp denna efter att den nya versionen är installerad.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Du uppdaterar till en ny huvudversion. Se till att du har läst ChangeLog för eventuella brkande ändringar.', + WARNING_SYSTEM_BACKUP: 'Detta kommer att skapa en säkerhetskopia av din fullständiga systemkonfiguration och inställningar. Alla lösenord kommer att vara läsbara i säkerhetskopien. Var försiktig med att dela! Vill du fortsätta?' + }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index f280a7183..4661b0b2f 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -186,7 +186,8 @@ const tr: Translation = { BUFFER_SIZE: 'En fazla bellek boyutu', COMPACT: 'Sıkışık', DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın', - DOWNLOAD_SETTINGS_TEXT2: 'Tüm verileri dışarı al', + DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al', + DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme', UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle', UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', @@ -357,7 +358,13 @@ const tr: Translation = { FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi', NO_DATA: 'Hiçbir veri yok', USER_PROFILE: 'Kullanıcı Profili', - STORED_VERSIONS: 'Kaydedilmiş Sürümler' + STORED_VERSIONS: 'Kaydedilmiş Sürümler', + ONLINE_HELP: 'online yardım', + UPGRADE_IMPORTANT_MESSAGES: 'Önemli Mesajları Güncelle', + UPGRADE_IMPORTANT_MESSAGES_1: 'Bu güncelleme továrnı ayarlarını gerektirir. Yapılandırmanızı ve ayarlarınızı önce yedekleyin ve ardından yeni sürüm yüklendikten sonra yükleyin.', + UPGRADE_IMPORTANT_MESSAGES_2: 'Yeni bir büyük sürüme yükselteceksiniz. Değişiklikleri ChangeLogı okuduğunuzdan emin olun.', + WARNING_SYSTEM_BACKUP: 'Bu, sistem yapılandırmanızı ve ayarlarınızın bir yedeklemesi oluşturacaktır. Tüm şifreler yedekleme dosyasında okunabilir olacaktır. Paylaşırken dikkatli olun! Devam etmek istediğinize emin misiniz?' + }; export default tr; diff --git a/interface/src/utils/file.ts b/interface/src/utils/file.ts index 547a30cad..3fa077c77 100644 --- a/interface/src/utils/file.ts +++ b/interface/src/utils/file.ts @@ -23,6 +23,8 @@ export const saveFile = ( }, 100); } catch (error) { console.error('Failed to save file:', error); - throw new Error(`Unable to save file: ${filename}${extension}`); + throw new Error(`Unable to save file: ${filename}${extension}`, { + cause: error + }); } }; diff --git a/interface/src/utils/useInterval.ts b/interface/src/utils/useInterval.ts index 82cbaaf1e..4ce7928da 100644 --- a/interface/src/utils/useInterval.ts +++ b/interface/src/utils/useInterval.ts @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -const DEFAULT_DELAY = 3000; +const DEFAULT_DELAY = 5000; /** * Custom hook for setting up an interval with proper cleanup diff --git a/interface/vite.config.ts b/interface/vite.config.ts index 2369cc845..0c16f6a7b 100644 --- a/interface/vite.config.ts +++ b/interface/vite.config.ts @@ -2,9 +2,8 @@ import preact from '@preact/preset-vite'; import fs from 'fs'; import path from 'path'; import { visualizer } from 'rollup-plugin-visualizer'; -import { Plugin, defineConfig } from 'vite'; +import { Plugin, PluginOption, defineConfig } from 'vite'; import viteImagemin from 'vite-plugin-imagemin'; -import viteTsconfigPaths from 'vite-tsconfig-paths'; import zlib from 'zlib'; // @ts-expect-error - mock server doesn't have type declarations @@ -99,16 +98,31 @@ const createPreactPlugin = (devToolsEnabled: boolean) => prefreshEnabled: false }); +// Patch preact/compat to export stub React 19 APIs (use, useOptimistic) so that +// react-router v7 doesn't trigger IMPORT_IS_UNDEFINED warnings from Rolldown. +const preactCompatPatchPlugin = (): Plugin => ({ + name: 'preact-compat-react19-patch', + transform(code, id) { + if (id.includes('preact') && id.includes('compat.module.js')) { + return { + code: + code + + '\nexport var use = undefined;\nexport var useOptimistic = undefined;\n', + map: null + }; + } + return undefined; + } +}); + // Common base plugins const createBasePlugins = ( devToolsEnabled: boolean, includeBundleReporter = true -) => { - const plugins = [ +): PluginOption[] => { + const plugins: PluginOption[] = [ createPreactPlugin(devToolsEnabled), - viteTsconfigPaths({ - projects: ['./tsconfig.json'] - }) + preactCompatPatchPlugin() ]; if (includeBundleReporter) { plugins.push(bundleSizeReporter()); @@ -234,7 +248,8 @@ export default defineConfig( plugins: [...createBasePlugins(true, true), mockServer()], resolve: { alias: RESOLVE_ALIASES, - extensions: RESOLVE_EXTENSIONS + extensions: RESOLVE_EXTENSIONS, + tsconfigPaths: true }, server: { open: true, @@ -263,7 +278,8 @@ export default defineConfig( plugins: createBasePlugins(false, true), resolve: { alias: RESOLVE_ALIASES, - extensions: RESOLVE_EXTENSIONS + extensions: RESOLVE_EXTENSIONS, + tsconfigPaths: true }, build: { ...createBaseBuildConfig(), @@ -297,7 +313,8 @@ export default defineConfig( ], resolve: { alias: RESOLVE_ALIASES, - extensions: RESOLVE_EXTENSIONS + extensions: RESOLVE_EXTENSIONS, + tsconfigPaths: true }, build: { ...createBaseBuildConfig(), @@ -306,8 +323,7 @@ export default defineConfig( rollupOptions: { treeshake: { moduleSideEffects: false, - propertyReadSideEffects: false, - tryCatchDeoptimization: false, + propertyReadSideEffects: false as const, unknownGlobalSideEffects: false }, output: { diff --git a/lib/OneWire/OneWire.h b/lib/OneWire/OneWire.h index 25618908a..7c4830afd 100644 --- a/lib/OneWire/OneWire.h +++ b/lib/OneWire/OneWire.h @@ -148,9 +148,7 @@ #elif defined(ARDUINO_ARCH_ESP32) #include #include -#if ESP_IDF_VERSION_MAJOR >= 5 #include "soc/gpio_periph.h" -#endif // ESP_IDF_VERSION_MAJOR >= 5 #define PIN_TO_BASEREG(pin) (0) #define PIN_TO_BITMASK(pin) (pin) #define IO_REG_TYPE uint32_t diff --git a/lib/esp32-psram/src/esp32-psram.h b/lib/esp32-psram/src/esp32-psram.h index a69d9f4cd..b7b6c436d 100644 --- a/lib/esp32-psram/src/esp32-psram.h +++ b/lib/esp32-psram/src/esp32-psram.h @@ -12,7 +12,9 @@ // Include all library components #include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector #include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector -#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector (ESP32 only) +#endif // #include "esp32-psram/InMemoryFile.h" // File interface using vectors // #include "esp32-psram/PSRAM.h" // PSRAM file system // #include "esp32-psram/HIMEM.h" // HIMEM file system diff --git a/lib/esp32-psram/src/esp32-psram/HimemBlock.h b/lib/esp32-psram/src/esp32-psram/HimemBlock.h index c6eb7d68a..f12b28b97 100644 --- a/lib/esp32-psram/src/esp32-psram/HimemBlock.h +++ b/lib/esp32-psram/src/esp32-psram/HimemBlock.h @@ -1,5 +1,8 @@ #pragma once +// HIMEM is only available on original ESP32 +#if CONFIG_IDF_TARGET_ESP32 + #include #include #include @@ -360,3 +363,5 @@ class HimemBlock { }; } // namespace esp32_psram + +#endif // CONFIG_IDF_TARGET_ESP32 diff --git a/lib/esp32-psram/src/esp32-psram/RingBufferStream.h b/lib/esp32-psram/src/esp32-psram/RingBufferStream.h index b32046789..b2062c562 100644 --- a/lib/esp32-psram/src/esp32-psram/RingBufferStream.h +++ b/lib/esp32-psram/src/esp32-psram/RingBufferStream.h @@ -238,7 +238,9 @@ using RingBufferStreamPSRAM = RingBufferStream>; /** * @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage */ +#if CONFIG_IDF_TARGET_ESP32 using RingBufferStreamHIMEM = RingBufferStream>; +#endif /** * @brief Type alias for a RingBufferStream that uses std::vector storage diff --git a/lib/esp32-psram/src/esp32-psram/TypedRingBuffer.h b/lib/esp32-psram/src/esp32-psram/TypedRingBuffer.h index 84ec9ab21..44f5344e0 100644 --- a/lib/esp32-psram/src/esp32-psram/TypedRingBuffer.h +++ b/lib/esp32-psram/src/esp32-psram/TypedRingBuffer.h @@ -209,8 +209,10 @@ using TypedRingBufferRAM = TypedRingBuffer>; /** * @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage */ +#if CONFIG_IDF_TARGET_ESP32 template using TypedRingBufferHIMEM = TypedRingBuffer>; +#endif /** * @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage diff --git a/lib/esp32-psram/src/esp32-psram/VectorHIMEM.h b/lib/esp32-psram/src/esp32-psram/VectorHIMEM.h index ed00d27d4..e3951a087 100644 --- a/lib/esp32-psram/src/esp32-psram/VectorHIMEM.h +++ b/lib/esp32-psram/src/esp32-psram/VectorHIMEM.h @@ -1,5 +1,8 @@ #pragma once +// HIMEM is only available on original ESP32 +#if CONFIG_IDF_TARGET_ESP32 + #include "HimemBlock.h" namespace esp32_psram { @@ -526,4 +529,6 @@ void swap(VectorHIMEM& lhs, VectorHIMEM& rhs) noexcept { lhs.swap(rhs); } -} // namespace esp32_psram \ No newline at end of file +} // namespace esp32_psram + +#endif // CONFIG_IDF_TARGET_ESP32 \ No newline at end of file diff --git a/lib/uuid-syslog/src/syslog.cpp b/lib/uuid-syslog/src/syslog.cpp index 024fa6665..4e0eac774 100644 --- a/lib/uuid-syslog/src/syslog.cpp +++ b/lib/uuid-syslog/src/syslog.cpp @@ -20,7 +20,7 @@ #include "../../src/core/emsesp.h" #ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP8266) // time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637 #define UUID_SYSLOG_HAVE_GETTIMEOFDAY 1 #endif diff --git a/lib_standalone/Arduino.cpp b/lib_standalone/Arduino.cpp index 16b286985..cf7651354 100644 --- a/lib_standalone/Arduino.cpp +++ b/lib_standalone/Arduino.cpp @@ -145,6 +145,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) { return 0; }; void ledcAttachPin(uint8_t pin, uint8_t chan) {}; +void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {}; void ledcWrite(uint8_t chan, uint32_t duty) {}; void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {}; void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {}; diff --git a/lib_standalone/Arduino.h b/lib_standalone/Arduino.h index d13411c24..e521fa40b 100644 --- a/lib_standalone/Arduino.h +++ b/lib_standalone/Arduino.h @@ -72,6 +72,7 @@ void analogSetAttenuation(adc_attenuation_t attenuation); void dacWrite(uint8_t pin, uint8_t value); double ledcSetup(uint8_t chan, double freq, uint8_t bit_num); void ledcAttachPin(uint8_t pin, uint8_t chan); +void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num); void ledcWrite(uint8_t chan, uint32_t duty); void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); diff --git a/lib_standalone/ArduinoJson.h b/lib_standalone/ArduinoJson.h index 5fbf79b27..89d56dd71 100644 --- a/lib_standalone/ArduinoJson.h +++ b/lib_standalone/ArduinoJson.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2025, Benoit BLANCHON +// Copyright © 2014-2026, Benoit BLANCHON // MIT License #pragma once @@ -239,11 +239,11 @@ #define ARDUINOJSON_BIN2ALPHA_1111() P #define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D() #define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D) -#define ARDUINOJSON_VERSION "7.4.2" +#define ARDUINOJSON_VERSION "7.4.3" #define ARDUINOJSON_VERSION_MAJOR 7 #define ARDUINOJSON_VERSION_MINOR 4 -#define ARDUINOJSON_VERSION_REVISION 2 -#define ARDUINOJSON_VERSION_MACRO V742 +#define ARDUINOJSON_VERSION_REVISION 3 +#define ARDUINOJSON_VERSION_MACRO V743 #ifndef ARDUINOJSON_VERSION_NAMESPACE #define ARDUINOJSON_VERSION_NAMESPACE \ ARDUINOJSON_CONCAT5(ARDUINOJSON_VERSION_MACRO, \ @@ -1536,11 +1536,12 @@ template struct FloatTraits {}; template struct FloatTraits { - using mantissa_type = uint64_t; - static const short mantissa_bits = 52; - static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; - using exponent_type = int16_t; - static const exponent_type exponent_max = 308; + using mantissa_type = uint64_t; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; + using exponent_type = int16_t; + static const exponent_type exponent_max = 308; + static const size_t binaryPowersOfTen = 9; static pgm_ptr positiveBinaryPowersOfTen() { ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // uint64_t, @@ -1601,11 +1602,12 @@ struct FloatTraits { }; template struct FloatTraits { - using mantissa_type = uint32_t; - static const short mantissa_bits = 23; - static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; - using exponent_type = int8_t; - static const exponent_type exponent_max = 38; + using mantissa_type = uint32_t; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; + using exponent_type = int8_t; + static const exponent_type exponent_max = 38; + static const size_t binaryPowersOfTen = 6; static pgm_ptr positiveBinaryPowersOfTen() { ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, @@ -1668,9 +1670,12 @@ template inline TFloat make_float(TFloat m, TExponent e) { using traits = FloatTraits; auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen() : traits::negativeBinaryPowersOfTen(); + auto count = traits::binaryPowersOfTen; if (e <= 0) e = TExponent(-e); for (uint8_t index = 0; e != 0; index++) { + if (index >= count) + return traits::nan(); if (e & 1) m *= powersOfTen[index]; e >>= 1; @@ -2422,7 +2427,7 @@ class VariantData { return; var->removeMember(key, resources); } - void reset() { + void reset() { // TODO: remove type_ = VariantType::Null; } void setBoolean(bool value) { @@ -4214,7 +4219,7 @@ template struct Comparer; template struct Comparer::value>> : ComparerBase { - T rhs; + T rhs; // TODO: store adapted string? explicit Comparer(T value) : rhs(value) { } @@ -5298,7 +5303,7 @@ class StringBuilder { append(*s++); } void append(const char * s, size_t n) { - while (n-- > 0) + while (n-- > 0) // TODO: memcpy append(*s++); } void append(char c) { diff --git a/mock-api/package.json b/mock-api/package.json index 5b8a4efed..c90493509 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -1,6 +1,6 @@ { "name": "mock-api", - "version": "3.8.0", + "version": "3.8.2", "description": "mock api for EMS-ESP", "author": "proddy, emsesp.org", "license": "MIT", @@ -12,8 +12,8 @@ "@msgpack/msgpack": "^3.1.3", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "formidable": "^3.5.4", - "itty-router": "^5.0.22", - "prettier": "^3.8.1" + "itty-router": "^5.0.23", + "prettier": "^3.8.3" }, - "packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264" + "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" } diff --git a/mock-api/pnpm-lock.yaml b/mock-api/pnpm-lock.yaml index fca4f0b02..d1f155ffa 100644 --- a/mock-api/pnpm-lock.yaml +++ b/mock-api/pnpm-lock.yaml @@ -13,16 +13,16 @@ importers: version: 3.1.3 '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.2 - version: 6.0.2(prettier@3.8.1) + version: 6.0.2(prettier@3.8.3) formidable: specifier: ^3.5.4 version: 3.5.4 itty-router: - specifier: ^5.0.22 - version: 5.0.22 + specifier: ^5.0.23 + version: 5.0.23 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.3 + version: 3.8.3 packages: @@ -30,8 +30,8 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.0': - resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': @@ -46,8 +46,8 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -112,8 +112,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -131,8 +131,8 @@ packages: resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} engines: {node: '>=14.0.0'} - itty-router@5.0.22: - resolution: {integrity: sha512-9hmdGErWdYDOurGYxSbqLhy4EFReIwk71hMZTJ5b+zfa2zjMNV1ftFno2b8VjAQvX615gNB8Qxbl9JMRqHnIVA==} + itty-router@5.0.23: + resolution: {integrity: sha512-i49WU+SNPrwOZA4Z61En1RYd5h2Lcqa+5IvCpMrNi4dxymzJK15ozUUnRrWIUAv95Zamd4eJPAot2UvHRrQg7w==} javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} @@ -145,11 +145,11 @@ packages: engines: {node: '>=6'} hasBin: true - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} ms@2.1.3: @@ -167,8 +167,8 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true @@ -183,9 +183,9 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/generator@7.29.0': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -197,22 +197,22 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.29.0': + '@babel/parser@7.29.2': dependencies: '@babel/types': 7.29.0 '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@babel/traverse@7.29.0': dependencies: '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3 @@ -246,17 +246,17 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)': + '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)': dependencies: - '@babel/generator': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 javascript-natural-sort: 0.7.1 - lodash-es: 4.17.23 - minimatch: 9.0.5 + lodash-es: 4.18.1 + minimatch: 9.0.9 parse-imports-exports: 0.2.4 - prettier: 3.8.1 + prettier: 3.8.3 transitivePeerDependencies: - supports-color @@ -264,7 +264,7 @@ snapshots: balanced-match@1.0.2: {} - brace-expansion@2.0.2: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 @@ -283,7 +283,7 @@ snapshots: dezalgo: 1.0.4 once: 1.4.0 - itty-router@5.0.22: {} + itty-router@5.0.23: {} javascript-natural-sort@0.7.1: {} @@ -291,11 +291,11 @@ snapshots: jsesc@3.1.0: {} - lodash-es@4.17.23: {} + lodash-es@4.18.1: {} - minimatch@9.0.5: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.0 ms@2.1.3: {} @@ -311,6 +311,6 @@ snapshots: picocolors@1.1.1: {} - prettier@3.8.1: {} + prettier@3.8.3: {} wrappy@1.0.2: {} diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 2c9504147..1e3a7afae 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -141,8 +141,8 @@ let system_status = { let DEV_VERSION_IS_UPGRADEABLE: boolean; let STABLE_VERSION_IS_UPGRADEABLE: boolean; let THIS_VERSION: string; -let LATEST_STABLE_VERSION = '3.8.0'; -let LATEST_DEV_VERSION = '3.8.1-dev.2'; +let LATEST_STABLE_VERSION = '3.8.2'; +let LATEST_DEV_VERSION = '3.8.3-dev.2'; // scenarios for testing versioning let version_test = 0; // on latest stable, or switch to dev @@ -363,6 +363,8 @@ function export_data(type: string) { return emsesp_modules; case 'allvalues': return emsesp_allvalues; + case 'systembackup': + return emsesp_systembackup; default: return status(404); } @@ -386,13 +388,34 @@ function custom_support() { '', "For help and questions please contact your installer." ], - img_url: 'https://emsesp.org/_media/images/designer.png' + img_url: 'https://emsesp.org/media/images/designer.png' // img_url: 'https://picsum.photos/200/300' } }; } -// called by Action endpoint +// called by Action endpoint upgradeImportantMessages +function upgradeImportantMessages(version: string) { + // 0 is do nothing + // 1 means 3.9 and factory reset required + // 2 means a major version upgrade + let upgradeImportantMessageType_n = 0; + + // see if its a filename with a .bin extension + if (version.endsWith('.bin')) { + upgradeImportantMessageType_n = 1; // 1 means 3.9 and factory reset required + } else if (version.endsWith('.md')) { + upgradeImportantMessageType_n = 0; + } else { + // this is a version string like "3.9.0" + upgradeImportantMessageType_n = 2; + } + + console.log('upgradeImportantMessageType: ' + upgradeImportantMessageType_n); + return { upgradeImportantMessageType: upgradeImportantMessageType_n }; +} + +// called by Action endpoint checkUpgrade function check_upgrade(version: string) { let data = {}; if (version) { @@ -732,6 +755,8 @@ const emsesp_info = { ] }; +const emsesp_systembackup = {}; + const emsesp_allvalues = { 'Boiler Nefit Trendline HRC30 (DeviceID:0x08, ProductID:123, Version:06.01)': { 'force heating off': 'off', @@ -4564,7 +4589,7 @@ router let sorted_devices = [...emsesp_coredata.devices].sort((a, b) => a.t - b.t); // append emsesp_coredata to sorted_devices so Custom is always at the end of the list sorted_devices.push(emsesp_coredata_custom); - // sorted_devices = []; // uncomment if simulating no devices... + // return { connected: false, devices: [] }; // uncomment if simulating no devices... return { connected: true, devices: sorted_devices }; }) .get(EMSESP_SENSOR_DATA_ENDPOINT, () => { @@ -5166,6 +5191,9 @@ router // set partition console.log('setting partition to', content.param); return status(200); + } else if (action === 'upgradeImportantMessages') { + // check upgrade important messages + return upgradeImportantMessages(content.param); } } return status(404); // cmd not found diff --git a/platformio.ini b/platformio.ini index 528c0822e..f30cfa721 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,15 +15,14 @@ description = EMS-ESP Firmware for the ESP32 src_dir = src lib_dir = lib boards_dir = boards -; build_cache_dir = .pio/build_cache extra_configs = factory_settings.ini pio_local.ini [common] -core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -core_unbuild_flags = -std=gnu++11 -fno-lto +core_build_flags = -std=c++17 -std=gnu++17 -O3 -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers +core_unbuild_flags = -std=gnu++11 my_build_flags = @@ -104,11 +103,10 @@ monitor_filters = direct build_type = release board_build.filesystem = littlefs lib_deps = - bblanchon/ArduinoJson @ 7.4.2 + bblanchon/ArduinoJson @ 7.4.3 ESP32Async/AsyncTCP @ 3.4.10 ESP32Async/ESPAsyncWebServer @ 3.10.3 - https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 - + ; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 ; builds the web interface only, not the firmware [env:build_webUI] @@ -199,6 +197,7 @@ build_src_filter = -<../lib/uuid-syslog> -<../lib/eModbus> -<../lib/OneWire> + -<../src/core/ModuleLibrary.cpp> lib_ldf_mode = off lib_deps = @@ -241,6 +240,7 @@ build_src_filter = -<../lib/uuid-syslog> -<../lib/eModbus> -<../lib/OneWire> + -<../src/core/ModuleLibrary.cpp> lib_ldf_mode = off lib_deps = Unity test_testing_command = diff --git a/project-words.txt b/project-words.txt index 62705f645..7a998c037 100644 --- a/project-words.txt +++ b/project-words.txt @@ -6,6 +6,9 @@ abluftqualität abluftqualitätsfühler abrt absburnpow +ACAC +ACAH +ACAO accomodate aceotrope activehigh @@ -64,7 +67,6 @@ asyncwebsocket asyncwebsynchronization atoint ausreichend -außenluft authmode autodst automode @@ -82,6 +84,7 @@ auxheatmix auxheatrmode auxlimitstart auxmaxlimit +außenluft avty awsc azubuike @@ -137,7 +140,6 @@ calinttemp catagory cbuf cerapur -česky cfamily changeloglevel chargeduration @@ -192,6 +194,7 @@ controlmode coolingcircuit coolingon coolingstarts +coolingtype cooloffdelay coolondelay coolstart @@ -669,12 +672,12 @@ lowpressure lowtopic lufqualität luft -lüfterstufe luftfeuchte luftfeuchtefühler luftqualfühl -lüftungsfrostschutz lukás +lüfterstufe +lüftungsfrostschutz maintenancedate maintenancemessage maintenancetime @@ -827,7 +830,6 @@ nwcl nystrom odata oddparity -öffnen offsettemp offtemp oilpreheat @@ -942,6 +944,9 @@ rawstr rcplus readback readelf +READYCLIENT +readymail +recp recved redtemp redthreshold @@ -1090,17 +1095,18 @@ staipassigned startshp starttemp starttemperature +starttls startvalue statusbyte stickbreaker stoffregen stoptime storagetemp -störung stringarray stringize studt studt's +störung suback substract summermode @@ -1126,6 +1132,7 @@ switchtimeww sycle syspress sysrettemp +systembackup systemstatus tado tapactivated @@ -1182,7 +1189,6 @@ trocken truefalse tsens tseslint -türk turnoffdiff turnondiff txen @@ -1200,6 +1206,7 @@ typehh typeids typel typesafe +türk uart ubauptime ucrt @@ -1252,7 +1259,6 @@ vorheizreg vpcooling vrey vybm -wärmetauscher washingmachine watchid wayon @@ -1301,6 +1307,7 @@ wwtemp wwtemplow wwvacations wwwhenmodeoff +wärmetauscher xclnt xiao xrtu @@ -1311,7 +1318,6 @@ yerger's yubox zadig zivanovic -živanović zlcn zolder zqhi @@ -1321,6 +1327,7 @@ zuluftebläse zuluftgebläse zulufttemp zyxwvutsrqponmlkjihgfedcba -ACAO -ACAH -ACAC +öffnen +česky +živanović +MWDT \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index cee91ae32..563719c80 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.organization=emsesp sonar.projectKey=emsesp_EMS-ESP32 sonar.projectName=EMS-ESP32 -sonar.projectVersion=3.8.0 +sonar.projectVersion=3.8.2 sonar.sources=./src sonar.cfamily.compile-commands=bw-output/compile_commands.json sonar.sourceEncoding=UTF-8 diff --git a/src/ESP32React/APSettingsService.h b/src/ESP32React/APSettingsService.h index 9b52f84d0..947911882 100644 --- a/src/ESP32React/APSettingsService.h +++ b/src/ESP32React/APSettingsService.h @@ -70,9 +70,9 @@ class APSettings { IPAddress subnetMask; bool operator==(const APSettings & settings) const { - return provisionMode == settings.provisionMode && channel == settings.channel && ssidHidden == settings.ssidHidden - && maxClients == settings.maxClients && localIP == settings.localIP && gatewayIP == settings.gatewayIP - && subnetMask == settings.subnetMask && ssid == settings.ssid && password == settings.password; + return provisionMode == settings.provisionMode && channel == settings.channel && ssidHidden == settings.ssidHidden && maxClients == settings.maxClients + && localIP == settings.localIP && gatewayIP == settings.gatewayIP && subnetMask == settings.subnetMask && ssid == settings.ssid + && password == settings.password; } static void read(const APSettings & settings, JsonObject root); diff --git a/src/ESP32React/ArduinoJsonJWT.cpp b/src/ESP32React/ArduinoJsonJWT.cpp index 6f87e926c..bbc2b11ac 100644 --- a/src/ESP32React/ArduinoJsonJWT.cpp +++ b/src/ESP32React/ArduinoJsonJWT.cpp @@ -66,21 +66,16 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) { } /* - * ESP32 uses mbedtls, with decent HMAC implementations supporting sha256, as well as others. - * No need to pull in additional crypto libraries - lets use what we already have. + * HMAC-SHA256 using mbedtls */ String ArduinoJsonJWT::sign(String & payload) { std::array hmacResult{}; - { - mbedtls_md_context_t ctx; - mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; - mbedtls_md_init(&ctx); - mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1); - mbedtls_md_hmac_starts(&ctx, reinterpret_cast(_secret.c_str()), _secret.length()); - mbedtls_md_hmac_update(&ctx, reinterpret_cast(payload.c_str()), payload.length()); - mbedtls_md_hmac_finish(&ctx, hmacResult.data()); - mbedtls_md_free(&ctx); - } + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), + reinterpret_cast(_secret.c_str()), + _secret.length(), + reinterpret_cast(payload.c_str()), + payload.length(), + hmacResult.data()); return encode(reinterpret_cast(hmacResult.data()), hmacResult.size()); } diff --git a/src/ESP32React/MqttSettingsService.cpp b/src/ESP32React/MqttSettingsService.cpp index 5bcaa9562..26754c118 100644 --- a/src/ESP32React/MqttSettingsService.cpp +++ b/src/ESP32React/MqttSettingsService.cpp @@ -256,7 +256,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) { StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) { MqttSettings newSettings; - bool changed = false; + bool changed = false; #ifndef TASMOTA_SDK newSettings.enableTLS = root["enableTLS"]; diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 4d016dce4..3d4e99152 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -61,22 +61,27 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri if (_is_firmware) { // Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 - if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32S2 - if (len > 12 && (data[0] != 0xE9 || data[12] != 2)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32S2)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32C3 - if (len > 12 && (data[0] != 0xE9 || data[12] != 5)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32C3)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32S3 - if (len > 12 && (data[0] != 0xE9 || data[12] != 9)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32S3)) { + handleError(request, 503); // service unavailable + return; + } +#elif CONFIG_IDF_TARGET_ESP32C6 + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32C6)) { handleError(request, 503); // service unavailable return; } @@ -179,7 +184,7 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) { } void UploadFileService::handleEarlyDisconnect() { - emsesp::EMSESP::logger().info("Upload ended"); + emsesp::EMSESP::logger().info("Upload finished"); emsesp::EMSESP::system_.uart_init(); // re-enable UART _is_firmware = false; diff --git a/src/core/ModuleLibrary.cpp b/src/core/ModuleLibrary.cpp new file mode 100644 index 000000000..1d0bff0ea --- /dev/null +++ b/src/core/ModuleLibrary.cpp @@ -0,0 +1,31 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2025 emsesp.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +void ModuleLibrary::list(JsonObject output) {}; + +void ModuleLibrary::loop() {}; + +void ModuleLibrary::start(emsesp::EMSESP * emsesp_main, bool test_mode) {}; + +bool ModuleLibrary::enable(const char * key, const char * license, bool enable) { + return true; +}; diff --git a/src/core/ModuleLibrary.h b/src/core/ModuleLibrary.h new file mode 100644 index 000000000..e9d410a4d --- /dev/null +++ b/src/core/ModuleLibrary.h @@ -0,0 +1,52 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2025 emsesp.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MODULELIBRARY_H +#define MODULELIBRARY_H + +#include + +#include +#include + +#include + +class ModuleLibrary { + public: + class Modules { + public: + Modules(const char * key, std::unique_ptr module) + : key(key) + , module(std::move(module)) { + } + const char * key; + std::unique_ptr module; + }; + + void start(emsesp::EMSESP * emsesp_main, bool test_mode = false); + void loop(); + void list(JsonObject output); + bool enable(const char * key, const char * license, bool enable); + + static uuid::log::Logger logger_; + + private: + std::vector modules_; +}; + +#endif diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 4147e5c34..49e2d250d 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -56,6 +56,7 @@ void IRAM_ATTR AnalogSensor::freqIrq2() { #endif void AnalogSensor::start(const bool factory_settings) { + // add hardcoded sensors for BBQKees gateway boards if (factory_settings && EMSESP::system_.board_profile() == "E32V2_2") { EMSESP::webCustomizationService.update([&](WebCustomization & settings) { auto newSensor = AnalogCustomization(); @@ -896,9 +897,9 @@ std::string AnalogSensor::get_metrics_prometheus() { result += (std::string) "\n# TYPE emsesp_" + sensor.name() + " gauge\n"; result += (std::string) "emsesp_" + sensor.name() + " "; if (sensor.type() != AnalogType::DIGITAL_OUT && sensor.type() != AnalogType::DIGITAL_IN) { - result += (std::string) Helpers::render_value(val, sensor.value(), 2) + "\n"; + result += (std::string)Helpers::render_value(val, sensor.value(), 2) + "\n"; } else { - result += (std::string) (sensor.value() == 0 ? "0\n" : "1\n"); + result += (std::string)(sensor.value() == 0 ? "0\n" : "1\n"); } } return result; diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 9286827b5..9d583e427 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -84,7 +84,7 @@ uuid::log::Logger EMSESP::logger() { RxService EMSESP::rxservice_; // incoming Telegram Rx handler TxService EMSESP::txservice_; // outgoing Telegram Tx handler Mqtt EMSESP::mqtt_; // mqtt handler -Modbus * EMSESP::modbus_; // modbus handler +Modbus * EMSESP::modbus_ = nullptr; // modbus handler System EMSESP::system_; // core system services TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors AnalogSensor EMSESP::analogsensor_; // Analog sensors @@ -1600,10 +1600,11 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { wait_km_ = true; connect_time = uuid::get_uptime_sec(); } + if (poll_id == EMSbus::ems_bus_id()) { - // TODO this could also be by coincidence, so we should add a counter to the EMSbus class to check if the poll_id is the same as the EMS_BUS_ID for a certain number of times EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active } + if (wait_km_) { if (poll_id != 0x48 && (uuid::get_uptime_sec() - connect_time) < EMS_WAIT_KM_TIMEOUT) { return; @@ -1709,6 +1710,11 @@ void EMSESP::start() { bool factory_settings = false; #endif + // start NVS storage + if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first + nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs + } + // set valid GPIOs list based on ESP32 chip/platform type system_.set_valid_system_gpios(); @@ -1757,7 +1763,7 @@ void EMSESP::start() { LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); #endif -// see if we're restoring a settings file + // see if we're restoring a settings file #ifndef EMSESP_STANDALONE if (system_.check_restore()) { LOG_WARNING("EMS-ESP will restart to apply new settings. Please wait."); @@ -1765,11 +1771,7 @@ void EMSESP::start() { }; #endif - if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first - nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs - } - - LOG_DEBUG("Fuse device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str()); + LOG_DEBUG("eFuse device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str()); webSettingsService.begin(); // load EMS-ESP Application settings @@ -1802,12 +1804,6 @@ void EMSESP::start() { #endif } - // start services - if (system_.modbus_enabled()) { - modbus_ = new Modbus; - modbus_->start(1, system_.modbus_port(), system_.modbus_max_clients(), system_.modbus_timeout() * 1000); - } - mqtt_.start(); // mqtt init system_.start(); // starts commands, led, adc, button, network (sets hostname), syslog & uart shower_.start(); // initialize shower timer and shower alert @@ -1854,7 +1850,7 @@ void EMSESP::loop() { return; // LED flashing is active, skip the rest of the loop } - esp32React.loop(); // web services like network, AP, MQTT + esp32React.loop(); // core services: Network, AP, MQTT and NTP webLogService.loop(); // log in Web UI // run the loop, unless we're in the middle of an OTA upload diff --git a/src/core/emsesp_common.h b/src/core/emsesp_common.h new file mode 100644 index 000000000..09d8ecc1a --- /dev/null +++ b/src/core/emsesp_common.h @@ -0,0 +1,91 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2025 emsesp.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EMSESP_COMMON_H +#define EMSESP_COMMON_H + +#include + +using uuid::log::Level; + +#if defined(EMSESP_DEBUG) +#define LOG_DEBUG(...) logger_.debug(__VA_ARGS__) +#else +#define LOG_DEBUG(...) +#endif + +#define LOG_INFO(...) logger_.info(__VA_ARGS__) +#define LOG_TRACE(...) logger_.trace(__VA_ARGS__) +#define LOG_NOTICE(...) logger_.notice(__VA_ARGS__) +#define LOG_WARNING(...) logger_.warning(__VA_ARGS__) +#define LOG_ERROR(...) logger_.err(__VA_ARGS__) + +// flash strings +using uuid::string_vector; +using string_vector = std::vector; + +#ifdef FPSTR +#undef FPSTR +#endif + +// clang-format off + + #define FPSTR(pstr_pointer) pstr_pointer + #define MAKE_WORD_CUSTOM(string_name, string_literal) static const char __pstr__##string_name[] = string_literal; + #define MAKE_WORD(string_name) MAKE_WORD_CUSTOM(string_name, #string_name) + + #define F_(string_name) (__pstr__##string_name) + #define FL_(list_name) (__pstr__L_##list_name) + + // Translation counter - capture baseline before any MAKE_TRANSLATION calls + enum { EMSESP_TRANSLATION_COUNT_START = __COUNTER__ }; + + // The language settings below must match system.cpp + #if defined(EMSESP_EN_ONLY) + // EN only + #define MAKE_WORD_TRANSLATION(list_name, en, ...) static const char * const __pstr__L_##list_name[] = {en, nullptr}; + #define MAKE_TRANSLATION(list_name, shortname, en, ...) static constexpr int __translation_counter_##list_name = __COUNTER__; static const char * const __pstr__L_##list_name[] = {shortname, en, nullptr}; + #elif defined(EMSESP_TEST) || defined(EMSESP_DE_ONLY) + // EN + DE (Test mode uses two languages to save flash memory) + #define MAKE_WORD_TRANSLATION(list_name, en, de, ...) static const char * const __pstr__L_##list_name[] = {en, de, nullptr}; + #define MAKE_TRANSLATION(list_name, shortname, en, de, ...) static constexpr int __translation_counter_##list_name = __COUNTER__; static const char * const __pstr__L_##list_name[] = {shortname, en, de, nullptr}; + #else + // All languages + #define MAKE_WORD_TRANSLATION(list_name, ...) static const char * const __pstr__L_##list_name[] = {__VA_ARGS__, nullptr}; + #define MAKE_TRANSLATION(list_name, ...) static constexpr int __translation_counter_##list_name = __COUNTER__; static const char * const __pstr__L_##list_name[] = {__VA_ARGS__, nullptr}; + #endif + + #define MAKE_NOTRANSLATION(list_name, ...) static const char * const __pstr__L_##list_name[] = {__VA_ARGS__, nullptr}; + + // fixed strings, no translations + #define MAKE_ENUM_FIXED(enum_name, ...) static const char * const __pstr__L_##enum_name[] = {__VA_ARGS__, nullptr}; + + // with translations + #define MAKE_ENUM(enum_name, ...) static const char * const * __pstr__L_##enum_name[] = {__VA_ARGS__, nullptr}; + +// clang-format on + +// load translations +#include "locale_translations.h" +#include "locale_common.h" + +// Translation count - dynamically calculated at compile-time +enum { EMSESP_TRANSLATION_COUNT_END = __COUNTER__ }; +static constexpr uint16_t EMSESP_TRANSLATION_COUNT = static_cast(EMSESP_TRANSLATION_COUNT_END) - static_cast(EMSESP_TRANSLATION_COUNT_START) - 1; + +#endif diff --git a/src/core/helpers.h b/src/core/helpers.h index 20f8fa122..5758b08b8 100644 --- a/src/core/helpers.h +++ b/src/core/helpers.h @@ -20,7 +20,7 @@ #define EMSESP_HELPERS_H #include "telegram.h" // for EMS_VALUE_* settings -#include "common.h" +#include "emsesp_common.h" namespace emsesp { diff --git a/src/core/locale_common.h b/src/core/locale_common.h index 2b769dd2c..d5b88c789 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -47,6 +47,7 @@ MAKE_WORD(raw) MAKE_WORD(watch) MAKE_WORD(syslog) MAKE_WORD(send) +MAKE_WORD(sendmail) MAKE_WORD(telegram) MAKE_WORD(bus_id) MAKE_WORD(tx_mode) diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h index 65cda4859..a56633592 100644 --- a/src/core/locale_translations.h +++ b/src/core/locale_translations.h @@ -32,10 +32,10 @@ #define EMSESP_LOCALE_SK "sk" #define EMSESP_LOCALE_CZ "cz" -// IMPORTANT! translations are in the order:,en, de, nl, sv, pl, no, fr, tr, it, sk, cz +// IMPORTANT! translations are in the order: en, de, nl, sv, pl, no, fr, tr, it, sk, cz // // if there is no translation, it will default to en -// + // device types, as display in Web and Console MAKE_WORD_TRANSLATION(boiler_hp_device, "Boiler/HP", "Kessel/WP", "CV ketel/WP", "Värmepanna/VP", "Kocioł/PC", "Varmekjele/VP", "Chaudière/PC", "Kazan/IP", "Caldaia/PC", "Kotol/TČ", "Kotel/TČ") MAKE_WORD_TRANSLATION(boiler_device, "Boiler", "Kessel", "CV ketel", "Värmepanna", "Kocioł", "Varmekjele", "Chaudière", "Kazan", "Caldaia", "Kotol", "Kotel") @@ -65,6 +65,7 @@ MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos" MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "lista all entiteter", "wyświetl wszsytkie encje", "Viser alle enheter", "lister toutes les entités", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity", "vypsat všechny entity") MAKE_WORD_TRANSLATION(metrics_cmd, "list all prometheus metrics", "Liste aller Prometheus Metriken", "lijst van alle Prometheus metriken", "lista alla Prometheus metriker", "wyświetl wszystkie Prometheus metryki", "Viser alle Prometheus metrikker", "lister toutes les métriques Prometheus", "Tüm Prometheus metriklerini listele", "elenca tutte le metriche Prometheus", "zobraziť všetky Prometheus metriky", "vypsat všechny Prometheus metriky") MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "skicka ett telegram", "wyślij telegram", "send et telegram", "envoyer un télégramme", "Bir telegram gönder", "invia un telegramma", "poslať telegram", "odeslat telegram") +MAKE_WORD_TRANSLATION(sendmail_cmd, "send email", "Sende eMail", "stuur email", "skicka email", "wyślij email", "send e-post", "envoyer un email", "email gönder", "invia email", "poslať email", "odeslat email") MAKE_WORD_TRANSLATION(read_cmd, "send read request", "Sende Leseanfrage", "stuur leesaanvraag", "skicka en läsförfrågan", "wyślij żądanie odczytu", "send leseforespørsel", "envoyer une demande de lecture", "okuma isteği gönder", "invia richiesta di lettura", "odoslať žiadosť o prečítanie", "odeslat požadavek na čtení") MAKE_WORD_TRANSLATION(setiovalue_cmd, "set I/O value", "Setze Werte E/A", "instellen standaardwaarde", "sätt ett I/O-värde", "ustaw wartość", "sett en io verdi", "définir valeur E/S", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io", "nastavit hodnotu I/O") MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "ändra logg-nivå", "zmień poziom log-u", "endre loggnivå", "changer le niveau de journal", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu", "změnit úroveň protokolování") @@ -104,6 +105,7 @@ MAKE_WORD_TRANSLATION(tag_dhw7, "dhw7", "WWK7", "dhw7", "VVK7", "CWU7", "dhw7", MAKE_WORD_TRANSLATION(tag_dhw8, "dhw8", "WWK8", "dhw8", "VVK8", "CWU8", "dhw8", "ecs8", "SKS8", "dhw8", "TÚV8", "TUV8") MAKE_WORD_TRANSLATION(tag_dhw9, "dhw9", "WWK9", "dhw9", "VVK9", "CWU9", "dhw9", "ecs9", "SKS9", "dhw9", "TÚV9", "TUV9") MAKE_WORD_TRANSLATION(tag_dhw10, "dhw10", "WWK10", "dhw10", "VVK10", "CWU10", "dhw10", "ecs10", "SKS10", "dhw10", "TÚV10", "TUV10") + // heatingsources MAKE_WORD_TRANSLATION(tag_ahs1, "ahs1", "AHQ1", "ahs1", "AVK1", "AŹC1", "ahs1", "ahs1", "ahs1", "ahs1", "ahs1", "ahs1") MAKE_WORD_TRANSLATION(tag_hs1, "hs1", "HQ1", "hs1", "VK1", "ŹC1", "hs1", "hs1", "hs1", "hs1", "hs1", "hs1") @@ -122,6 +124,7 @@ MAKE_WORD_TRANSLATION(tag_hs13, "hs13", "HQ13", "hs13", "VK13", "ŹC13", "hs13", MAKE_WORD_TRANSLATION(tag_hs14, "hs14", "HQ14", "hs14", "VK14", "ŹC14", "hs14", "hs14", "hs14", "hs14", "hs14", "hs14") MAKE_WORD_TRANSLATION(tag_hs15, "hs15", "HQ15", "hs15", "VK15", "ŹC15", "hs15", "hs15", "hs15", "hs15", "hs15", "hs15") MAKE_WORD_TRANSLATION(tag_hs16, "hs16", "HQ16", "hs16", "VK16", "ŹC16", "hs16", "hs16", "hs16", "hs16", "hs16", "hs16") + // single room thermostats MAKE_WORD_TRANSLATION(tag_src1, "src1", "SRC1") MAKE_WORD_TRANSLATION(tag_src2, "src2", "SRC2") @@ -426,11 +429,9 @@ MAKE_TRANSLATION(pumpCharacter, "pumpcharacter", "boiler pump characteristic", " MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogiktemperatur", "pomplogica temperatuur", "Pumplogiktemperatur", "temperatura logiki pompy", "pumpelogikktemperatur", "température logique pompe", "pompa mantık sıcaklığı", "temperatura logica pompa", "teplota logiky čerpadla", "teplota logiky čerpadla") MAKE_TRANSLATION(headertemp, "headertemp", "low loss header", "Hydr. Weiche", "open verdeler", "Fördelare", "sprzęgło hydrauliczne", "lav tap header", "bouteille de déc. hydr.", "isı bloğu gidiş suyu sıc.", "comp. idr.", "nízkostratová hlavica", "hydraulický oddělovač") MAKE_TRANSLATION(heatblock, "heatblock", "heating block", "Wärmezelle", "Aanvoertemp. warmtecel", "Värmeblock", "blok grzewczy", "varmeblokk", "départ corps de chauffe", "Hid.denge kabı sıcaklığı", "mandata scamb. pr.", "vykurovací blok", "blok topení") - MAKE_TRANSLATION(pumpKickHour, "pumpkickhour", "pump kick hour", "Stunde Pumpkick") MAKE_TRANSLATION(pumpKickDay, "pumpkickday", "pump kick day", "Tag Pumpkick") MAKE_TRANSLATION(pumpKickDelay, "pumpkickdelay", "pump kick delay", "Pause vor Pumpkick") - MAKE_TRANSLATION(curveOn, "curveon", "heatingcurve on", "Heizkurve an", "stookkromme aan", "Värmekurva På", "krzywa grzewcza włączona", "varmekurve på", "courbe de chauffage activée", "ısıtma eğrisi açık", "curva di riscaldamento attiva", "vykurovacia krivka zapnutá", "topná křivka zapnutá") MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", "stookkromme basis", "Värmekurva Bas", "podstawa krzywej grzewczej", "varmekurve basis", "base de courbe de chauffage", "ısıtma eğrisi tabanı", "base curva di riscaldamento", "základňa vykurovacej krivky", "základ topné křivky") MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "stookkromme einde", "Värmekurva Slut", "koniec krzywej grzewczej", "varmekurve slutt", "fin de courbe de chauffage", "ısıtma eğrisi sonu", "fine curva di riscaldamento", "koniec vykurovacej krivky", "konec topné křivky") @@ -478,7 +479,6 @@ MAKE_TRANSLATION(hpActivity, "hpactivity", "compressor activity", "Kompressorakt MAKE_TRANSLATION(hpTargetSpd, "hptargetspd", "compressor target speed", "Kompressorsolldrehzahl", "", "", "", "", "", "", "", "kompresor cieľové otáčky", "cílová rychlost kompresoru") MAKE_TRANSLATION(receiverValveVr0, "recvalve", "receiver valve VR0", "Eingangsventil VR0", "", "", "", "", "", "", "", "prijímač ventil VR0", "přijímací ventil VR0") MAKE_TRANSLATION(expansionValveVr1, "expvalve", "expansion valve VR1", "Ausdehnungsventil VR1", "", "", "", "", "", "", "", "prijímač ventil VR1", "přijímací ventil VR1") - MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru") MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru") MAKE_TRANSLATION(hpPower, "hppower", "compressor power output", "Kompressorleistung", "Compressorvermogen", "Kompressoreffekt", "moc wyjściowa sprężarki", "kompressoreffekt", "puissance de sortie compresseur", "ısı pompası güç çıkışı", "potenza uscita compressore", "výkon kompresora", "výstupní výkon kompresoru") @@ -496,7 +496,6 @@ MAKE_TRANSLATION(hpPl1, "hppl1", "low pressure side temperature (PL1)", "Niederd MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdrucktemperatur (PH1)", "Temperatuur hoge drukzijde (PH1)", "Temperatur Högtryckssidan (PH1)", "temperatura po stronie wysokiego ciśnienia (PH1)", "Temperatur Høytrykksiden (PH1)", "température côté bhauteasse pression (PH1)", "yüksek basınç tarafı sıcaklığı (PH1)", "temperatura lato alta pressione (PH1)", "teplota na strane vysokého tlaku (PH1)", "teplota na vysokotlaké straně (PH1)") MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)") MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)") - MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1", "stav vstupu 1") MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2", "stav vstupu 2") MAKE_TRANSLATION(hpInput3, "hpin3", "input 3 state", "Status Eingang 3", "Status input 3", "Status Ingång 3", "stan wejścia 3", "status inggang 3", "état entrée 3", "giriş 3 durumu", "stato ingresso 3", "stav vstupu 3", "stav vstupu 3") @@ -508,7 +507,6 @@ MAKE_TRANSLATION(hpIn4Opt, "hpin4opt", "input 4 options", "Einstellung Eingang 4 MAKE_TRANSLATION(maxHeatComp, "maxheatcomp", "heat limit compressor", "Heizstab Limit mit Kompressor", "heat limit compressor", "Max. Värmegräns Kompressor", "ograniczenie mocy sprężarki", "max varmegrense kompressor", "limite chaleur compresseur", "ısı pompası ısıtma sınırı", "limite riscaldamento compressore", "tepelný limit kompresora", "tepelný limit kompresoru") MAKE_TRANSLATION(maxHeatHeat, "maxheatheat", "heat limit heating", "Heizstab Limit Leistung", "Max, Värmegräns Uppvärmning", "heat limit heating", "ograniczenie mocy w trybie ogrzewania", "maks varmegrense oppvarming", "limite chaleur chauffage", "ısınma ısıtma sınırı", "limite calore riscaldamento", "vyhrievanie limitu tepla", "tepelný limit topení") MAKE_TRANSLATION(maxHeatDhw, "maxheat", "heat limit", "Heizstab Limit für WW", "heat limit", "Max. Värmegräns Varmvatten", "ograniczenie mocy w trybie c.w.u.", "varmegrense", "limite chaleur", "sıcak kullanım suyu ısınma sınırı", "limite calore", "tepelný limit", "tepelný limit") - MAKE_TRANSLATION(auxHeaterOff, "auxheateroff", "disable aux heater", "Zusatzheizer deaktivieren", "Bijverwarming uitsc", "Blockera eltillskott", "wyłącz dogrzewacz", "deaktiver tilleggsvarme", "Désactiver chauff. d'app", "ilave ısıtıcıyı kapat", "disattivare i riscaldatori addizionali", "vypnúť pomocný ohrievač", "zakázat pomocné topení") MAKE_TRANSLATION(auxHeaterStatus, "auxheaterstatus", "aux heater status", "Zusatzheizerstatus", "Bijverwarming", "Eltillskott Status", "status dogrzewacza", "status el. tillegsvarme", "Chauffage auxiliaire", "ilave ısıtıcı durumu", "stato riscaldatori addizionali", "stav pomocného ohrievača", "stav pomocného topení") MAKE_TRANSLATION(auxHeaterLevel, "auxheaterlevel", "aux heater level", "Zusatzheizer", "Bijverwarming", "Eltillskott", "dogrzewacza", "el. tillegsvarme", "Chauffage auxiliaire", "ilave ısıtıcı durumu", "riscaldatori addizionali", "pomocného ohrievača", "pomocného topení") @@ -525,7 +523,6 @@ MAKE_TRANSLATION(tempDiffHeat, "tempdiffheat", "temp diff TC3/TC0 heat", "Temp.d MAKE_TRANSLATION(tempDiffCool, "tempdiffcool", "temp diff TC3/TC0 cool", "Temp.diff. TC3/TC0 Kühlen", "Temp.vers. TC3/TC0 koel.", "Temperaturskillnad TC3/TC0 Kyla", "różnica temperatur TC3/TC0 w trakcie chłodzenia", "temp. diff. TC3/TC0 kjøling", "Delta T TC3/TC0 Refroid.", "TC3-TC0 soğutma sıcaklık farkı", "Delta T raffreddamento TC3/TC0", "teplotný rozdiel TC3/TC0 chladenie", "rozdíl teplot TC3/TC0 pro chlazení") MAKE_TRANSLATION(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start", "Start stille modus", "Tyst drift starttid", "początek trybu cichego", "stillemodus starter", "", "sessiz mod başlangıcı", "avvio della modalità silenziosa", "tichý režim od", "tichý režim od") MAKE_TRANSLATION(silentTo, "silentto", "silent mode to", "Silentmodus Ende", "Einde stille modus", "Tyst drift stopptid", "koniec trybu cichego", "komfortmodus av", "", "sessiz mod bitişi", "spegnere modalità silenziosa", "tichý režim do", "tichý režim do") - MAKE_TRANSLATION(wwComfOffTemp, "comfoff", "comfort switch off", "Komfort Ausschalttemp.", "Comfort Uitschakeltemp.", "Komfort frånkopplingstemperatur", "temperatura wyłączania w trybie komfort", "eco modus utkoblingstem", "Confort Temp. d'arrêt", "konfor kapalı", "spegnimento modalità comfort", "komfortné vypnutie", "komfortní vypnutí") MAKE_TRANSLATION(wwEcoOffTemp, "ecooff", "eco switch off", "ECO Ausschalttemp.", "Eco Uitschakeltemp.", "Eko frånkopplingstemperatur", "temperatura wyłączania w trybie eko", "Øko avstengningstemp.", "Eco Temp. d'arrêt", "eko kapalı", "spegnimento modalità ECO", "eko vypínač", "eko vypnutí") MAKE_TRANSLATION(wwEcoPlusOffTemp, "ecoplusoff", "eco+ switch off", "ECO+ Ausschalttemp.", "Eco+ Uitschakeltemp.", "Eko+ frånkopplingstemperatur", "temperatura wyłączania w trybie eko+", "Øko+ avstengningstemp.", "Eco+ Temp. d'arrêt", "eko+ kapalı", "spegnimento modalità ECO+", "eko+ vypnutie", "eko+ vypnutí") @@ -535,7 +532,6 @@ MAKE_TRANSLATION(wwEcoPlusDiffTemp, "ecoplusdiff", "eco+ diff", "ECO+ Differenzt MAKE_TRANSLATION(wwComfStopTemp, "comfstop", "comfort stop temp", "Komfort Stopptemp.", "", "Komfort stopptemperatur", "", "", "", "", "", "komfortná stop teplota", "komfortní teplota vypnutí") MAKE_TRANSLATION(wwEcoStopTemp, "ecostop", "eco stop temp", "ECO Stopptemp.", "", "Eko stopptemperatur", "", "", "", "", "", "ECO stop teplota", "eko teplota vypnutí") MAKE_TRANSLATION(wwEcoPlusStopTemp, "ecoplusstop", "eco+ stop temp", "ECO+ Stopptemp.", "", "Eko+ stopptemperatur", "", "", "", "", "", "ECO+ stop teplota", "eko+ teplota vypnutí") - MAKE_TRANSLATION(auxHeatMode, "auxheatrmode", "aux heater mode", "Zusatzheizungsmodus", "Modus bijverwarmer", "Eltillskott Läge", "tryb pracy dogrzewacza po blokadzie z Zakładu Energetycznego", "tilleggsvarmer modus", "", "ilave ısıtıcı modu", "modalità riscaldatore addizionale", "režim pomocného ohrievača", "režim pomocného topení") MAKE_TRANSLATION(auxMaxLimit, "auxmaxlimit", "aux heater max limit", "Zusatzheizer max. Grenze", "Bijverwarmer grensinstelling maximaal", "Eltillskott max begränsning", "dogrzewacz, maksymalny limit", "tillegsvarme maksgrense", "ilave ısıtıcı maks limit", "limite massimo riscaldatore addizionale", "maximálny limit pomocného ohrievača", "maximální limit pomocného topení") MAKE_TRANSLATION(auxLimitStart, "auxlimitstart", "aux heater limit start", "Zusatzheizer Grenze Start", "Bijverwarmer grens voor start", "Eltillskott begränsningsstart", "dogrzewacz, początek ograniczenia", "tillegsvarme startgrense", "ilave ısıtıcı limir başlangıcı", "avvio limite massimo riscaldatore addizionale", "spustenie limitu pomocného ohrievača", "startovací limit pomocného topení") @@ -832,7 +828,6 @@ MAKE_TRANSLATION(absent, "absent", "absent", "Abwesend", "", "Frånvarande", "", MAKE_TRANSLATION(redthreshold, "redthreshold", "reduction threshold", "Absenkschwelle", "", "Tröskel för sänkning", "", "", "", "", "", "zníženie tresholdu", "práh snížení") MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluß", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv") MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "current solar influence", "akt. Solareinfluß", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv") - MAKE_TRANSLATION(hpmode, "hpmode", "HP Mode", "WP-Modus", "Modus warmtepomp", "Värmepumpsläge", "tryb pracy pompy ciepła", "", "", "yüksek güç modu", "Modalità Termopompa", "Režim TČ", "režim tepelného čerpadla") MAKE_TRANSLATION(dewoffset, "dewoffset", "dew point offset", "Taupunktdifferenz", "Offset dauwpunt", "Daggpunktsförskjutning", "przesunięcie punktu rosy", "", "", "çiğ noktası göreli", "differenza del punto di rugiada", "posun rosného bodu", "offset rosného bodu") MAKE_TRANSLATION(roomtempdiff, "roomtempdiff", "room temp difference", "Raumtemperaturdifferenz", "Verschiltemperatuur kamertemp", "Rumstemperaturskillnad", "różnica temp. pomieszczenia", "", "", "oda sıcaklığı farkı", "differenza temperatura ambiente", "rozdiel izbovej teploty", "rozdíl teploty místnosti") diff --git a/src/core/modbus.cpp b/src/core/modbus.cpp index 803ab80d4..bec679a22 100644 --- a/src/core/modbus.cpp +++ b/src/core/modbus.cpp @@ -52,7 +52,7 @@ void Modbus::stop() { #ifndef EMSESP_STANDALONE modbusServer_->stop(); // virtual ~ModbusServerTCPasync() = default; - // delete modbusServer_; + delete modbusServer_; modbusServer_ = nullptr; #endif } diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index b73f4ef25..7c63923f3 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -1184,7 +1184,8 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "temperature"; // override uom if fahrenheit - doc[uom_ha] = EMSESP::system_.fahrenheit() ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT] : DeviceValue::DeviceValueUOM_s[uom]; + doc[uom_ha] = EMSESP::system_.fahrenheit() && uom != DeviceValueUOM::K ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT] + : DeviceValue::DeviceValueUOM_s[uom]; break; case DeviceValueUOM::PERCENT: if (display_only) { diff --git a/src/core/system.cpp b/src/core/system.cpp index 777db8fd8..3000b50f6 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -20,8 +20,13 @@ #include "emsesp.h" // for send_raw_telegram() command #ifndef EMSESP_STANDALONE +#include "esp_image_format.h" #include "esp_ota_ops.h" #include "esp_partition.h" +#include +#include "esp_efuse.h" +#include +#include #endif #include @@ -33,11 +38,6 @@ #include "../test/test.h" #endif -#ifndef EMSESP_STANDALONE -#include -#include "esp_efuse.h" -#endif - namespace emsesp { // Languages supported. Note: the order is important @@ -338,7 +338,13 @@ void System::get_partition_info() { strftime(time_string, sizeof(time_string), "%FT%T", localtime(&d)); p_info.install_date = d > 1500000000L ? time_string : ""; - p_info.size = part->size / 1024; // set size in KB + esp_image_metadata_t meta = {}; + esp_partition_pos_t part_pos = {.offset = part->address, .size = part->size}; + if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &part_pos, &meta) == ESP_OK) { + p_info.size = meta.image_len / 1024; // actual firmware size in KB + } else { + p_info.size = 0; + } partition_info_[part->label] = p_info; } @@ -362,7 +368,7 @@ void System::set_partition_install_date() { snprintf(c, sizeof(c), "d_%s", current_partition); time_t d = EMSESP::nvs_.getULong(c, 0); if (d < 1500000000L) { - LOG_INFO("Firmware is fresh, setting the new install date in partition %s", current_partition); + LOG_DEBUG("Setting the install date in partition %s", current_partition); auto t = time(nullptr) - uuid::get_uptime_sec(); EMSESP::nvs_.putULong(c, t); } @@ -406,9 +412,9 @@ bool System::set_partition(const char * partitionname) { // restart EMS-ESP // app0 or app1, or boot/factory on 16MB boards void System::system_restart(const char * partitionname) { -#ifndef EMSESP_STANDALONE // see if we are forcing a partition to use if (partitionname != nullptr) { +#ifndef EMSESP_STANDALONE // Factory partition - label will be "factory" const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); if (partition && !strcmp(partition->label, partitionname)) { @@ -439,27 +445,28 @@ void System::system_restart(const char * partitionname) { // set the boot partition esp_ota_set_boot_partition(partition); } +#endif LOG_INFO("Restarting EMS-ESP from %s partition", partitionname); } else { LOG_INFO("Restarting EMS-ESP..."); } - // make sure it's only executed once - EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); - store_nvs_values(); // save any NVS values - Shell::loop_all(); // flush log to output + + // flush all the log + EMSESP::webLogService.loop(); // dump all to web log + for (int i = 0; i < 10; i++) { + Shell::loop_all(); + delay(10); // give telnet TCP stack time to transmit + } + Serial.flush(); // wait for hardware TX buffer to drain + Mqtt::disconnect(); // gracefully disconnect MQTT, needed for QOS1 EMSuart::stop(); // stop UART so there is no interference - delay(1000); // wait 1 second - ESP.restart(); // ka-boom! -#else - EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); - if (partitionname != nullptr) { - LOG_INFO("Restarting EMS-ESP from %s partition", partitionname); - } else { - LOG_INFO("Restarting EMS-ESP..."); - } + +#ifndef EMSESP_STANDALONE + delay(1000); // wait 1 second + ESP.restart(); // ka-boom! - this is the only place where the ESP32 restart is called #endif } @@ -538,11 +545,6 @@ void System::store_settings(WebSettings & settings) { board_profile_ = settings.board_profile; telnet_enabled_ = settings.telnet_enabled; - modbus_enabled_ = settings.modbus_enabled; - modbus_port_ = settings.modbus_port; - modbus_max_clients_ = settings.modbus_max_clients; - modbus_timeout_ = settings.modbus_timeout; - tx_mode_ = settings.tx_mode; syslog_enabled_ = settings.syslog_enabled; syslog_level_ = settings.syslog_level; @@ -563,6 +565,25 @@ void System::store_settings(WebSettings & settings) { locale_ = settings.locale; developer_mode_ = settings.developer_mode; + + // start services + if (settings.modbus_enabled) { + if (EMSESP::modbus_ == nullptr) { + EMSESP::modbus_ = new Modbus; + EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000); + } else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) { + EMSESP::modbus_->stop(); + EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000); + } + } else if (EMSESP::modbus_ != nullptr) { + EMSESP::modbus_->stop(); + delete EMSESP::modbus_; + EMSESP::modbus_ = nullptr; + } + modbus_enabled_ = settings.modbus_enabled; + modbus_port_ = settings.modbus_port; + modbus_max_clients_ = settings.modbus_max_clients; + modbus_timeout_ = settings.modbus_timeout; } // Starts up core services @@ -1195,9 +1216,16 @@ void System::show_system(uuid::console::Shell & shell) { } // GPIOs shell.println(" GPIOs:"); + shell.printf(" allowed:"); + for (const auto & gpio : valid_system_gpios_) { + shell.printf(" %d", gpio); + } + shell.printfln(" [total %d]", valid_system_gpios_.size()); shell.printf(" in use:"); - for (const auto & usage : used_gpios_) { - shell.printf(" %d(%s)", usage.pin, usage.source.c_str()); + auto sorted_gpios = used_gpios_; + std::sort(sorted_gpios.begin(), sorted_gpios.end(), [](const GpioUsage & a, const GpioUsage & b) { return a.pin < b.pin; }); + for (const auto & gpio : sorted_gpios) { + shell.printf(" %d(%s)", gpio.pin, gpio.source.c_str()); } shell.printfln(" [total %d]", used_gpios_.size()); auto available = available_gpios(); @@ -1216,7 +1244,7 @@ void System::show_system(uuid::console::Shell & shell) { partition.first.c_str(), partition.second.version.c_str(), partition.second.size, - partition.second.install_date.empty() ? "" : (std::string(", installed ") + partition.second.install_date).c_str(), + partition.second.install_date.empty() ? "" : (std::string(", installed on ") + partition.second.install_date).c_str(), (strcmp(esp_ota_get_running_partition()->label, partition.first.c_str()) == 0) ? "** active **" : ""); } @@ -1335,23 +1363,134 @@ bool System::check_restore() { JsonObject input = jsonDocument.as(); // see what type of file it is, either settings or customization. anything else is ignored std::string settings_type = input["type"]; - if (settings_type == "settings") { - // It's a settings file. Parse each section separately. If it's system related it will require a reboot - reboot_required = saveSettings(NETWORK_SETTINGS_FILE, "Network", input); - reboot_required |= saveSettings(AP_SETTINGS_FILE, "AP", input); - reboot_required |= saveSettings(MQTT_SETTINGS_FILE, "MQTT", input); - reboot_required |= saveSettings(NTP_SETTINGS_FILE, "NTP", input); - reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, "Security", input); - reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, "Settings", input); + LOG_INFO("Restoring '%s' settings...", settings_type.c_str()); + + // system backup, which is a consolidated json object with all the settings files + if (settings_type == "systembackup") { + reboot_required = true; + JsonArray sections = input["systembackup"].as(); + for (JsonObject section : sections) { + std::string section_type = section["type"]; + LOG_DEBUG("Restoring '%s' section...", section_type.c_str()); + if (section_type == "settings") { + saveSettings(NETWORK_SETTINGS_FILE, section); + saveSettings(AP_SETTINGS_FILE, section); + saveSettings(MQTT_SETTINGS_FILE, section); + saveSettings(NTP_SETTINGS_FILE, section); + saveSettings(SECURITY_SETTINGS_FILE, section); + saveSettings(EMSESP_SETTINGS_FILE, section); + } + if (section_type == "schedule") { + saveSettings(EMSESP_SCHEDULER_FILE, section); + } + if (section_type == "customizations") { + saveSettings(EMSESP_CUSTOMIZATION_FILE, section); + } + if (section_type == "entities") { + saveSettings(EMSESP_CUSTOMENTITY_FILE, section); + } + if (section_type == "modules") { + saveSettings(EMSESP_MODULES_FILE, section); + } + if (section_type == "customSupport") { + // it's a custom support, extract json and write to /config/customSupport.json file + File customSupportFile = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "w"); + if (customSupportFile) { + serializeJson(section, customSupportFile); + customSupportFile.close(); + LOG_INFO("Custom support file updated"); + } else { + LOG_ERROR("Failed to save custom support file"); + } + } + + if (section_type == "nvs") { + // Restore NVS values + JsonArray nvs_entries = section["nvs"].as(); + for (JsonObject entry : nvs_entries) { + std::string key = entry["key"] | ""; + int type = entry["type"] | NVS_TYPE_ANY; + + switch (type) { + case NVS_TYPE_I8: + if (entry["value"].is()) { + int8_t v = entry["value"]; + EMSESP::nvs_.putChar(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_U8: + if (entry["value"].is()) { + uint8_t v = entry["value"]; + EMSESP::nvs_.putUChar(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_I32: + if (entry["value"].is()) { + int32_t v = entry["value"]; + EMSESP::nvs_.putInt(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_U32: + if (entry["value"].is()) { + uint32_t v = entry["value"]; + EMSESP::nvs_.putUInt(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_I64: + if (entry["value"].is()) { + int64_t v = entry["value"]; + EMSESP::nvs_.putLong64(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_U64: + if (entry["value"].is()) { + uint64_t v = entry["value"]; + EMSESP::nvs_.putULong64(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_BLOB: + // used for double values + if (entry["value"].is()) { + double v = entry["value"]; + EMSESP::nvs_.putDouble(key.c_str(), v); + LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v); + } + break; + case NVS_TYPE_STR: + case NVS_TYPE_ANY: + default: + if (entry["value"].is()) { + std::string v = entry["value"]; + EMSESP::nvs_.putString(key.c_str(), v.c_str()); + LOG_DEBUG("Restored NVS value: %s = %s", key.c_str(), v.c_str()); + } + break; + } + } + } + } + } + + // It's a single settings file. Parse each section separately. If it's system related it will require a reboot + else if (settings_type == "settings") { + reboot_required = saveSettings(NETWORK_SETTINGS_FILE, input); + reboot_required |= saveSettings(AP_SETTINGS_FILE, input); + reboot_required |= saveSettings(MQTT_SETTINGS_FILE, input); + reboot_required |= saveSettings(NTP_SETTINGS_FILE, input); + reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, input); + reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, input); } else if (settings_type == "customizations") { - // it's a customization file, just replace it and there's no need to reboot - saveSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", input); + saveSettings(EMSESP_CUSTOMIZATION_FILE, input); } else if (settings_type == "schedule") { - // it's a schedule file, just replace it and there's no need to reboot - saveSettings(EMSESP_SCHEDULER_FILE, "Schedule", input); + saveSettings(EMSESP_SCHEDULER_FILE, input); } else if (settings_type == "entities") { - // it's a entity file, just replace it and there's no need to reboot - saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input); + saveSettings(EMSESP_CUSTOMENTITY_FILE, input); } else if (settings_type == "customSupport") { // it's a custom support file - save it to /config new_file.close(); @@ -1509,39 +1648,218 @@ bool System::check_upgrade() { return false; // no reboot required } -// convert settings file into json object -void System::extractSettings(const char * filename, const char * section, JsonObject output) { +// map each config filename to its human-readable section key #ifndef EMSESP_STANDALONE +static const std::pair SECTION_MAP[] = { + {NETWORK_SETTINGS_FILE, "Network"}, + {AP_SETTINGS_FILE, "AP"}, + {MQTT_SETTINGS_FILE, "MQTT"}, + {NTP_SETTINGS_FILE, "NTP"}, + {SECURITY_SETTINGS_FILE, "Security"}, + {EMSESP_SETTINGS_FILE, "Settings"}, + {EMSESP_SCHEDULER_FILE, "Schedule"}, + {EMSESP_CUSTOMIZATION_FILE, "Customizations"}, + {EMSESP_CUSTOMENTITY_FILE, "Entities"}, + {EMSESP_MODULES_FILE, "Modules"}, +}; +#endif + +// convert a single config file into a section of the output json object +void System::exportSettings(const std::string & type, const char * filename, JsonObject output) { + if (type != "settings") { + output["type"] = type; // add the type to the output, not for settings as it's already added because its grouped + } + +#ifndef EMSESP_STANDALONE + const char * section = nullptr; + for (const auto & [f, label] : SECTION_MAP) { + if (strcmp(f, filename) == 0) { + section = label; + break; + } + } + + if (!section) { + return; + } + File settingsFile = LittleFS.open(filename); if (settingsFile) { JsonDocument jsonDocument; DeserializationError error = deserializeJson(jsonDocument, settingsFile); if (error == DeserializationError::Ok && jsonDocument.is()) { - JsonObject jsonObject = jsonDocument.as(); - JsonObject node = output[section].to(); - for (JsonPair kvp : jsonObject) { + JsonObject node = output[section].to(); + for (JsonPair kvp : jsonDocument.as()) { node[kvp.key()] = kvp.value(); } + } else { + LOG_ERROR("Failed to deserialize settings file %s", filename); } + LOG_DEBUG("Exported %s settings from file %s", section, filename); + settingsFile.close(); + } else { + LOG_ERROR("No settings file for %s found", filename); } - settingsFile.close(); #endif } -// save settings file using input from a json object -bool System::saveSettings(const char * filename, const char * section, JsonObject input) { +// full system backup of all settings files +void System::exportSystemBackup(JsonObject output) { + output["type"] = "systembackup"; // add the type to the output + output["version"] = EMSESP_APP_VERSION; // add the version to the output + #ifndef EMSESP_STANDALONE + // add date/time if NTP enabled and active + if ((esp_sntp_enabled()) && (EMSESP::system_.ntp_connected())) { + time_t now = time(nullptr); + if (now > 1500000000L) { + char t[25]; + strftime(t, sizeof(t), "%FT%T", localtime(&now)); + output["date"] = t; + } + } +#endif + + // create an array of objects for each settings file + JsonArray nodes = output["systembackup"].to(); + + // start with settings by grouping them together + JsonObject node = nodes.add(); + node["type"] = "settings"; // add type once for this group + exportSettings("settings", NETWORK_SETTINGS_FILE, node); + exportSettings("settings", AP_SETTINGS_FILE, node); + exportSettings("settings", MQTT_SETTINGS_FILE, node); + exportSettings("settings", NTP_SETTINGS_FILE, node); + exportSettings("settings", SECURITY_SETTINGS_FILE, node); + exportSettings("settings", EMSESP_SETTINGS_FILE, node); + + node = nodes.add(); + exportSettings("schedule", EMSESP_SCHEDULER_FILE, node); + node = nodes.add(); + exportSettings("customizations", EMSESP_CUSTOMIZATION_FILE, node); + node = nodes.add(); + exportSettings("entities", EMSESP_CUSTOMENTITY_FILE, node); + node = nodes.add(); + exportSettings("modules", EMSESP_MODULES_FILE, node); + +#ifndef EMSESP_STANDALONE + // special case for custom support + File file = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "r"); + if (file) { + JsonDocument jsonDocument; + DeserializationError error = deserializeJson(jsonDocument, file); + if (error == DeserializationError::Ok && jsonDocument.is()) { + JsonObject node = nodes.add(); + node["type"] = "customSupport"; + node["data"] = jsonDocument.as(); + } + file.close(); + LOG_DEBUG("Exported custom support file %s", EMSESP_CUSTOMSUPPORT_FILE); + } + + // Backup NVS values + node = nodes.add(); + node["type"] = "nvs"; + + const char * nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs1") ? "nvs1" : "nvs"; // nvs1 is on 16MBs + nvs_iterator_t it = nullptr; +#if ESP_IDF_VERSION_MAJOR < 5 + it = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY); + if (it == nullptr) { +#else + esp_err_t err = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY, &it); + if (err != ESP_OK) { +#endif + LOG_ERROR("Failed to find NVS entry for %s", nvs_part); + return; + } + + JsonArray entries = node["nvs"].to(); +#if ESP_IDF_VERSION_MAJOR < 5 + while (it != nullptr) { + nvs_entry_info_t info; + nvs_entry_info(it, &info); +#else + while (err == ESP_OK) { + nvs_entry_info_t info; + nvs_entry_info(it, &info); +#endif + JsonObject entry = entries.add(); + entry["type"] = info.type; + entry["key"] = info.key; + + LOG_DEBUG("Exporting NVS value: %s = %d", info.key, info.type); + + switch (info.type) { + case NVS_TYPE_I8: + entry["value"] = EMSESP::nvs_.getChar(info.key); + break; + case NVS_TYPE_U8: + entry["value"] = EMSESP::nvs_.getUChar(info.key); + break; + case NVS_TYPE_I32: + entry["value"] = EMSESP::nvs_.getInt(info.key); + break; + case NVS_TYPE_U32: + entry["value"] = EMSESP::nvs_.getUInt(info.key); + break; + case NVS_TYPE_I64: + entry["value"] = EMSESP::nvs_.getLong64(info.key); + break; + case NVS_TYPE_U64: + entry["value"] = EMSESP::nvs_.getULong64(info.key); + break; + case NVS_TYPE_BLOB: + entry["value"] = EMSESP::nvs_.getDouble(info.key); // bytes used for double values + break; + case NVS_TYPE_STR: + case NVS_TYPE_ANY: + default: + entry["value"] = EMSESP::nvs_.getString(info.key); + break; + } + +#if ESP_IDF_VERSION_MAJOR < 5 + it = nvs_entry_next(it); + } +#else + err = nvs_entry_next(&it); + } +#endif + + if (it != nullptr) { + nvs_release_iterator(it); + } +#endif +} + +// write a settings file using input from a json object, called from upload/restore +bool System::saveSettings(const char * filename, JsonObject input) { +#ifndef EMSESP_STANDALONE + const char * section = nullptr; + for (const auto & [f, label] : SECTION_MAP) { + if (strcmp(f, filename) == 0) { + section = label; + break; + } + } + + if (!section) { + return false; + } + JsonObject section_json = input[section]; if (section_json) { File section_file = LittleFS.open(filename, "w"); if (section_file) { - LOG_INFO("Applying new uploaded %s data", section); + LOG_DEBUG("Applying new uploaded %s data", section); serializeJson(section_json, section_file); section_file.close(); return true; // reboot required } } #endif + return false; // not found } @@ -2047,17 +2365,28 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["txpause"] = EMSbus::tx_mode() == EMS_TXMODE_OFF; // GPIO information + std::string gpios_allowed_str; + for (const auto & gpio : valid_system_gpios_) { + if (!gpios_allowed_str.empty()) { + gpios_allowed_str += ", "; + } + gpios_allowed_str += Helpers::itoa(gpio); + } + node["gpios_allowed"] = gpios_allowed_str; + std::string gpios_in_use_str; - for (const auto & usage : EMSESP::system_.used_gpios_) { + auto sorted_gpios = used_gpios_; + std::sort(sorted_gpios.begin(), sorted_gpios.end(), [](const GpioUsage & a, const GpioUsage & b) { return a.pin < b.pin; }); + for (const auto & gpio : sorted_gpios) { if (!gpios_in_use_str.empty()) { gpios_in_use_str += ", "; } - gpios_in_use_str += Helpers::itoa(usage.pin); + gpios_in_use_str += Helpers::itoa(gpio.pin); } node["gpios_in_use"] = gpios_in_use_str; std::string gpios_available_str; - for (const auto & gpio : EMSESP::system_.available_gpios()) { + for (const auto & gpio : available_gpios()) { if (!gpios_available_str.empty()) { gpios_available_str += ", "; } @@ -2193,6 +2522,15 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output } #endif + // Modbus Status + node = output["modbus"].to(); + node["enabled"] = EMSESP::system_.modbus_enabled_; + if (EMSESP::system_.modbus_enabled_) { + node["maxClients"] = EMSESP::system_.modbus_max_clients_; + node["port"] = EMSESP::system_.modbus_port_; + node["timeout"] = EMSESP::system_.modbus_timeout_; + } + // Sensor Status node = output["sensor"].to(); if (EMSESP::sensor_enabled()) { @@ -2200,6 +2538,10 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["temperatureSensorReads"] = EMSESP::temperaturesensor_.reads(); node["temperatureSensorFails"] = EMSESP::temperaturesensor_.fails(); } + + // Analog Status + node = output["analog"].to(); + node["enabled"] = EMSESP::analog_enabled(); if (EMSESP::analog_enabled()) { node["analogSensors"] = EMSESP::analogsensor_.count_entities(); node["analogSensorReads"] = EMSESP::analogsensor_.reads(); @@ -2528,7 +2870,7 @@ std::string System::reset_reason(uint8_t cpu) const { case RESET_REASON_CORE_DEEP_SLEEP: return ("Deep sleep reset"); case 6: // RESET_REASON_CORE_SDIO: // not on S2, S3, C3 - return ("Reset by SDIO"); + return ("Reset by SDIO"); case RESET_REASON_CORE_MWDT0: return ("Timer group0 watch dog reset"); case RESET_REASON_CORE_MWDT1: @@ -2582,7 +2924,7 @@ bool System::ntp_connected() { return ntp_connected_; } -// see if its a BBQKees Gateway by checking the nvs values +// see if its a BBQKees Gateway by checking the eFuse values String System::getBBQKeesGatewayDetails(uint8_t detail) { #ifndef EMSESP_STANDALONE union { @@ -2918,7 +3260,7 @@ void System::set_valid_system_gpios() { valid_system_gpios_ = string_range_to_vector("0-21", "2, 8, 12-17, 18-19"); #elif CONFIG_IDF_TARGET_ESP32S2 - // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html // excluded: // GPIO26 - GPIO32 = SPI flash and PSRAM // GPIO45 - GPIO46 = strapping pins @@ -2931,7 +3273,7 @@ void System::set_valid_system_gpios() { valid_system_gpios_ = string_range_to_vector("0-46", "19, 20, 26-32, 45-46, 39-42, 22-25"); #elif CONFIG_IDF_TARGET_ESP32S3 - // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html // excluded: // GPIO3, GPIO45 - GPIO46 = strapping pins // GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended @@ -2950,7 +3292,7 @@ void System::set_valid_system_gpios() { } #elif CONFIG_IDF_TARGET_ESP32 - // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html // excluded: // GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM (dio mode only GPIO06-GPIO08, GPIO11) // GPIO20, GPIO24, GPIO28 - GPIO31 = don't exist diff --git a/src/core/system.h b/src/core/system.h index ba9c33120..d05645a37 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -156,8 +156,9 @@ class System { void systemStatus(uint8_t status_code); uint8_t systemStatus(); - static void extractSettings(const char * filename, const char * section, JsonObject output); - static bool saveSettings(const char * filename, const char * section, JsonObject input); + static void exportSettings(const std::string & type, const char * filename, JsonObject output); + static void exportSystemBackup(JsonObject output); + static bool saveSettings(const char * filename, JsonObject input); static bool add_gpio(uint8_t pin, const char * source_name); static std::vector available_gpios(); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 889276ad7..95170fbb7 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1759,8 +1759,12 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { ttime = mktime(tm_); // thermostat time } struct timeval newnow = {.tv_sec = ttime, .tv_usec = 0}; +#if CONFIG_IDF_TARGET_ESP32C3 + // unknown how to set time on C3 +#else settimeofday(&newnow, nullptr); LOG_INFO("ems-esp time set from thermostat"); +#endif } #endif } diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 5077987b7..bfa8e598e 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.8.2-dev.12" +#define EMSESP_APP_VERSION "3.8.2-dev.13" diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 3e141f084..a3c51c711 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -68,6 +68,14 @@ void EMSuart::uart_event_task(void * pvParameters) { // initialize UART driver void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) { if (tx_mode_ == EMS_TXMODE_INIT) { +#if CONFIG_IDF_TARGET_ESP32C6 + uart_config_t uart_config = {.baud_rate = EMSUART_BAUD, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0}; +#else uart_config_t uart_config = {.baud_rate = EMSUART_BAUD, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, @@ -80,6 +88,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t .flags = {0, 0} #endif }; +#endif #if defined(EMSUART_RX_INVERT) inverse_mask |= UART_SIGNAL_RXD_INV; #endif diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 03d5e95ee..c0b0b8d04 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -491,6 +491,8 @@ void WebSettings::set_board_profile(WebSettings & settings) { settings.board_profile = "S2MINI"; #elif CONFIG_IDF_TARGET_ESP32S3 settings.board_profile = "S32S3"; // BBQKees Gateway S3 +#elif CONFIG_IDF_TARGET_ESP32C6 + settings.board_profile = "CUSTOM"; #endif // apply the new board profile setting System::load_board_profile(data, settings.board_profile.c_str()); @@ -500,9 +502,9 @@ void WebSettings::set_board_profile(WebSettings & settings) { #ifndef EMSESP_STANDALONE uint32_t psram_size = ESP.getPsramSize() / 1024; // in KB if (psram_size > 0) { - EMSESP::logger().info("Loaded board profile %s, PSRAM: %lu KB", settings.board_profile.c_str(), psram_size); + EMSESP::logger().info("Loaded board profile %s (PSRAM: %lu KB)", settings.board_profile.c_str(), psram_size); } else { - EMSESP::logger().info("Loaded board profile %s, PSRAM: not available", settings.board_profile.c_str()); + EMSESP::logger().info("Loaded board profile %s (PSRAM: not available)", settings.board_profile.c_str()); } #endif diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 4cb923348..23f4d3486 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -216,6 +216,9 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) } else if (action == "resetMQTT" && is_admin) { EMSESP::mqtt_.reset_mqtt(); ok = true; + } else if (action == "upgradeImportantMessages") { + root["upgradeImportantMessageType"] = upgradeImportantMessages(param); + ok = true; } #if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY) @@ -237,13 +240,75 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) request->send(response); } +// action = upgradeImportantMessages +// returns the type of upgrade important message to display in the UI +// 0 = no message (if just a minor version upgrade) +// 1 = going from <= 3.8 to 3.9 (has new partition layout) +// 2 = major version upgrade +// version can be like 3.8.2 or a filename like EMS-ESP-3_8_2-dev_13-ESP32-16MB+.bin +uint8_t WebStatusService::upgradeImportantMessages(std::string & version) { + if (version.empty()) { + return 0; + } + + // it's a filename with a .bin or .md extension, try and extract the version from it + // e.g. EMS-ESP-3_8_2-dev_13-ESP32-16MB+.bin -> major=3 minor=8 patch=2 + version::Semver200_version latest_version; + if ((version.find(".bin") != std::string::npos) || (version.find(".md") != std::string::npos)) { + std::string filename = version; + auto pos = filename.find("EMS-ESP-"); + if (pos == std::string::npos) { + EMSESP::logger().err("Invalid version string: %s", version.c_str()); + return 0; + } + + pos += 8; // skip past "EMS-ESP-" + auto underscore1 = filename.find('_', pos); + auto underscore2 = filename.find('_', underscore1 + 1); + auto dash = filename.find('-', underscore2 + 1); + if (underscore1 == std::string::npos || underscore2 == std::string::npos || dash == std::string::npos) { + EMSESP::logger().err("Invalid version string: %s", version.c_str()); + return 0; + } + + std::string major_version = filename.substr(pos, underscore1 - pos); + std::string minor_version = filename.substr(underscore1 + 1, underscore2 - underscore1 - 1); + std::string patch_version = filename.substr(underscore2 + 1, dash - underscore2 - 1); + latest_version = version::Semver200_version(major_version + "." + minor_version + "." + patch_version); + } else { + // if it's .json file exit + if (version.find(".json") != std::string::npos) { + return 0; + } else { + // treat it like a version string like "3.9.0" + latest_version = version::Semver200_version(version); + } + } + + version::Semver200_version current_version(current_version_s); // get current version + + if (latest_version > current_version && current_version.minor() < latest_version.minor()) { + return 0; // if it's just a minor version upgrade return 0 + } + + if ((current_version.major() <= 3 && current_version.minor() <= 8) && (latest_version.major() == 3 && latest_version.minor() == 9)) { + return 1; // if moving from below 3.8.x to 3.9.x return 1 + } + + if (latest_version > current_version && current_version.major() < latest_version.major()) { + return 2; // if it's a major version upgrade return 2 + } + + return 0; // if it's not a valid version upgrade return 0 +} + // action = checkUpgrade // versions holds the latest development version and stable version in one string, comma separated -bool WebStatusService::checkUpgrade(JsonObject root, std::string & versions) { - if (!versions.empty()) { +bool WebStatusService::checkUpgrade(JsonObject root, std::string & version) { + if (!version.empty()) { version::Semver200_version current_version(current_version_s); - version::Semver200_version latest_dev_version(versions.substr(0, versions.find(','))); - version::Semver200_version latest_stable_version(versions.substr(versions.find(',') + 1)); + version::Semver200_version latest_dev_version(version.substr(0, version.find(','))); + version::Semver200_version latest_stable_version(version.substr(version.find(',') + 1)); bool dev_upgradeable = latest_dev_version > current_version; bool stable_upgradeable = latest_stable_version > current_version; @@ -310,26 +375,24 @@ void WebStatusService::allvalues(JsonObject output) { // action = export // returns data for a specific feature/settings as a json object bool WebStatusService::exportData(JsonObject root, std::string & type) { - root["type"] = type; - if (type == "settings") { - JsonObject node = root["System"].to(); - node["version"] = EMSESP_APP_VERSION; - System::extractSettings(NETWORK_SETTINGS_FILE, "Network", root); - System::extractSettings(AP_SETTINGS_FILE, "AP", root); - System::extractSettings(MQTT_SETTINGS_FILE, "MQTT", root); - System::extractSettings(NTP_SETTINGS_FILE, "NTP", root); - System::extractSettings(SECURITY_SETTINGS_FILE, "Security", root); - System::extractSettings(EMSESP_SETTINGS_FILE, "Settings", root); + root["type"] = type; // add settings as a group + System::exportSettings(type, NETWORK_SETTINGS_FILE, root); + System::exportSettings(type, AP_SETTINGS_FILE, root); + System::exportSettings(type, MQTT_SETTINGS_FILE, root); + System::exportSettings(type, NTP_SETTINGS_FILE, root); + System::exportSettings(type, SECURITY_SETTINGS_FILE, root); + System::exportSettings(type, EMSESP_SETTINGS_FILE, root); } else if (type == "schedule") { - System::extractSettings(EMSESP_SCHEDULER_FILE, "Schedule", root); + System::exportSettings(type, EMSESP_SCHEDULER_FILE, root); } else if (type == "customizations") { - System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root); + System::exportSettings(type, EMSESP_CUSTOMIZATION_FILE, root); } else if (type == "entities") { - System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); + System::exportSettings(type, EMSESP_CUSTOMENTITY_FILE, root); } else if (type == "allvalues") { - root.clear(); // don't need the "type" key added to the output allvalues(root); + } else if (type == "systembackup") { + System::exportSystemBackup(root); } else { return false; // error } @@ -344,7 +407,7 @@ bool WebStatusService::getCustomSupport(JsonObject root) { #if defined(EMSESP_STANDALONE) // dummy test data for "test api3" - deserializeJson(doc, "{\"type\":\"customSupport\",\"Support\":{\"html\":[\"html code\",\"here\"], \"img_url\": \"https://emsesp.org/_media/images/designer.png\"}"); + deserializeJson(doc, "{\"type\":\"customSupport\",\"Support\":{\"html\":[\"html code\",\"here\"], \"img_url\": \"https://emsesp.org/media/images/designer.png\"}"); #else // check if we have custom support file uploaded File file = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "r"); @@ -367,7 +430,7 @@ bool WebStatusService::getCustomSupport(JsonObject root) { #endif #if defined(EMSESP_DEBUG) - EMSESP::logger().debug("Showing custom support page"); + EMSESP::logger().debug("Sending custom support page"); #endif root.set(doc.as()); // add to web response root object diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h index 0d38a5b73..8d2c69bfd 100644 --- a/src/web/WebStatusService.h +++ b/src/web/WebStatusService.h @@ -30,12 +30,13 @@ class WebStatusService { SecurityManager * _securityManager; // actions - bool checkUpgrade(JsonObject root, std::string & latest_version); - bool exportData(JsonObject root, std::string & type); - bool getCustomSupport(JsonObject root); - bool uploadURL(const char * url); - bool setSystemStatus(const char * status); - void allvalues(JsonObject output); + bool checkUpgrade(JsonObject root, std::string & latest_version); + bool exportData(JsonObject root, std::string & type); + bool getCustomSupport(JsonObject root); + bool uploadURL(const char * url); + bool setSystemStatus(const char * status); + void allvalues(JsonObject output); + uint8_t upgradeImportantMessages(std::string & version); std::string current_version_s = EMSESP_APP_VERSION; }; diff --git a/test/test_api/test_api.h b/test/test_api/test_api.h index 1773ef272..e59282622 100644 --- a/test/test_api/test_api.h +++ b/test/test_api/test_api.h @@ -17,10 +17,9 @@ void test_2() { "[{\"info\":\"list all values (verbose)\",\"values\":\"list all values\",\"commands\":\"list all commands\",\"entities\":\"list all " "entities\",\"boil2hystoff\":\"hysteresis stage 2 off temperature\",\"boil2hyston\":\"hysteresis stage 2 on temperature\",\"boilhystoff\":\"hysteresis " "off temperature\",\"boilhyston\":\"hysteresis on temperature\",\"burnmaxpower\":\"burner max power\",\"burnminperiod\":\"burner min " - "period\",\"chimneysweeper\":\"chimney sweeper\",\"coldshot\":\"send a cold shot of " - "water\",\"curvebase\":\"heatingcurve base\",\"curveend\":\"heatingcurve end\",\"curveon\":\"heatingcurve " - "on\",\"dhw[n].activated\":\"activated\",\"dhw[n].chargeoptimization\":\"charge optimization\",\"dhw[n].circ\":\"circulation " - "active\",\"dhw[n].circmode\":\"circulation pump mode\",\"dhw[n].circpump\":\"circulation pump " + "period\",\"chimneysweeper\":\"chimney sweeper\",\"coldshot\":\"send a cold shot of water\",\"curvebase\":\"heatingcurve " + "base\",\"curveend\":\"heatingcurve end\",\"curveon\":\"heatingcurve on\",\"dhw[n].activated\":\"activated\",\"dhw[n].chargeoptimization\":\"charge " + "optimization\",\"dhw[n].circ\":\"circulation active\",\"dhw[n].circmode\":\"circulation pump mode\",\"dhw[n].circpump\":\"circulation pump " "available\",\"dhw[n].comfort\":\"comfort\",\"dhw[n].comfort1\":\"comfort mode\",\"dhw[n].dhwprio\":\"dhw " "priority\",\"dhw[n].disinfecting\":\"disinfecting\",\"dhw[n].disinfectiontemp\":\"disinfection temperature\",\"dhw[n].flowtempoffset\":\"flow " "temperature offset\",\"dhw[n].hystoff\":\"hysteresis off temperature\",\"dhw[n].hyston\":\"hysteresis on temperature\",\"dhw[n].maxpower\":\"max " @@ -32,9 +31,9 @@ void test_2() { "date\",\"maintenancetime\":\"time to next maintenance\",\"nofrostmode\":\"nofrost mode\",\"nofrosttemp\":\"nofrost " "temperature\",\"nompower\":\"nominal Power\",\"nrgheat\":\"energy heating\",\"pumpcharacter\":\"boiler pump characteristic\",\"pumpdelay\":\"pump " "delay\",\"pumpkickday\":\"pump kick day\",\"pumpkickdelay\":\"pump kick delay\",\"pumpkickhour\":\"pump kick hour\",\"pumpmode\":\"boiler pump " - "mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump " - "logic temperature\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow " - "temperature\",\"summertemp\":\"summer temperature\"}]"; + "mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump logic " + "temperature\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow temperature\",\"summertemp\":\"summer " + "temperature\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/commands")); } @@ -149,9 +148,9 @@ void test_12() { } void test_13() { - auto expected_response = "[{\"hc1\":{\"seltemp\":20.5,\"currtemp\":22.8,\"modetype\":\"heat\",\"remotetemp\":null},\"hc2\":{" - "\"seltemp\":20.6,\"currtemp\":22.9,\"modetype\":\"eco\",\"remotetemp\":null},\"hc3\":{\"seltemp\":20." - "7,\"currtemp\":23,\"modetype\":\"nofrost\",\"remotetemp\":null},\"dhw\":{}}]"; + auto expected_response = + "[{\"hc1\":{\"seltemp\":20.5,\"currtemp\":22.8,\"modetype\":\"heat\",\"remotetemp\":null},\"hc2\":{\"seltemp\":20.6,\"currtemp\":22.9,\"modetype\":" + "\"eco\",\"remotetemp\":null},\"hc3\":{\"seltemp\":20.7,\"currtemp\":23,\"modetype\":\"nofrost\",\"remotetemp\":null},\"dhw\":{}}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat")); } @@ -164,11 +163,10 @@ void test_15() { auto expected_response = "[{\"api_data\":\"# HELP emsesp_seltemp selected room temperature, °C, readable, writeable, visible\\n# TYPE emsesp_seltemp " "gauge\\nemsesp_seltemp{circuit=\\\"hc1\\\"} 20.50\\n# HELP emsesp_currtemp current room temperature, °C, readable, visible\\n# TYPE emsesp_currtemp " - "gauge\\nemsesp_currtemp{circuit=\\\"hc1\\\"} 22.80\\n# HELP emsesp_modetype mode type, enum, (0: " - "nofrost; 1: eco; 2: heat), readable, visible\\n# TYPE emsesp_modetype gauge\\nemsesp_modetype{circuit=\\\"hc1\\\"} " - "2\\nemsesp_seltemp{circuit=\\\"hc2\\\"} 20.60\\nemsesp_currtemp{circuit=\\\"hc2\\\"} " - "22.90\\nemsesp_modetype{circuit=\\\"hc2\\\"} 1\\nemsesp_seltemp{circuit=\\\"hc3\\\"} 20.70\\nemsesp_currtemp{circuit=\\\"hc3\\\"} " - "23\\nemsesp_modetype{circuit=\\\"hc3\\\"} 0\\n\"}]"; + "gauge\\nemsesp_currtemp{circuit=\\\"hc1\\\"} 22.80\\n# HELP emsesp_modetype mode type, enum, (0: nofrost; 1: eco; 2: heat), readable, visible\\n# " + "TYPE emsesp_modetype gauge\\nemsesp_modetype{circuit=\\\"hc1\\\"} 2\\nemsesp_seltemp{circuit=\\\"hc2\\\"} " + "20.60\\nemsesp_currtemp{circuit=\\\"hc2\\\"} 22.90\\nemsesp_modetype{circuit=\\\"hc2\\\"} 1\\nemsesp_seltemp{circuit=\\\"hc3\\\"} " + "20.70\\nemsesp_currtemp{circuit=\\\"hc3\\\"} 23\\nemsesp_modetype{circuit=\\\"hc3\\\"} 0\\n\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/thermostat/metrics")); } @@ -217,23 +215,24 @@ void test_22() { void test_23() { auto expected_response = "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " - "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"\"}," - "\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," - "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," - "\"tzLabel\":\"Europe/" + "Unknown\",\"txpause\":false,\"gpios_allowed\":\"0, 2, 5, 18, 23\",\"gpios_in_use\":\"0, 2, 5, 18, " + "23\",\"gpios_available\":\"\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false," + "\"lowBandwidth\":false,\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true," + "\"server\":\"pool.ntp.org\",\"tzLabel\":\"Europe/" "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," "\"MQTTPublishes\":0,\"MQTTQueued\":0,\"MQTTPublishFails\":0,\"MQTTReconnects\":0,\"enabled\":true,\"clientID\":\"ems-esp\",\"keepAlive\":60," "\"cleanSession\":false,\"entityFormat\":1,\"base\":\"ems-esp\",\"discoveryPrefix\":\"homeassistant\",\"discoveryType\":0,\"nestedFormat\":1," "\"haEnabled\":true,\"mqttQos\":0,\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10," "\"publishTimeSolar\":10,\"publishTimeMixer\":10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false," - "\"publish2command\":false,\"sendResponse\":false},\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":3,\"temperatureSensorReads\":0," - "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" - "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," - "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" - "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," - "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," - "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" - "\"boiler\",\"name\":\"My Custom " + "\"publish2command\":false,\"sendResponse\":false},\"syslog\":{\"enabled\":false},\"modbus\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":3," + "\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0," + "\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\"," + "\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0," + "\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11," + "\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":" + "false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true," + "\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My " + "Custom " "Boiler\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":39,\"handlersReceived\":\"0x18\"," "\"handlersFetched\":\"0x14 0x33\",\"handlersPending\":\"0xBF 0x10 0x11 0xC2 0xC6 0x15 0x1C 0x19 0x1A 0x35 0x34 0x2A 0xD1 0xE3 0xE4 0xE5 0xE9 0x02E0 " "0x2E " @@ -247,23 +246,24 @@ void test_23() { void test_24() { auto expected_response = "[{\"system\":{\"version\":\"dev\",\"uptime\":\"000+00:00:00.000\",\"uptimeSec\":0,\"resetReason\":\"Unknown / " - "Unknown\",\"txpause\":false,\"gpios_in_use\":\"23, 5, 2, 18, 0\",\"gpios_available\":\"\"}," - "\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false,\"lowBandwidth\":false," - "\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true,\"server\":\"pool.ntp.org\"," - "\"tzLabel\":\"Europe/" + "Unknown\",\"txpause\":false,\"gpios_allowed\":\"0, 2, 5, 18, 23\",\"gpios_in_use\":\"0, 2, 5, 18, " + "23\",\"gpios_available\":\"\"},\"network\":{\"network\":\"WiFi\",\"hostname\":\"ems-esp\",\"RSSI\":-23,\"TxPowerSetting\":0,\"staticIP\":false," + "\"lowBandwidth\":false,\"disableSleep\":true,\"enableMDNS\":true,\"enableCORS\":false},\"ntp\":{\"NTPstatus\":\"disconnected\",\"enabled\":true," + "\"server\":\"pool.ntp.org\",\"tzLabel\":\"Europe/" "London\",\"NTPStatus\":\"disconnected\"},\"ap\":{\"provisionMode\":\"always\",\"ssid\":\"ems-esp\"},\"mqtt\":{\"MQTTStatus\":\"disconnected\"," "\"MQTTPublishes\":0,\"MQTTQueued\":0,\"MQTTPublishFails\":0,\"MQTTReconnects\":0,\"enabled\":true,\"clientID\":\"ems-esp\",\"keepAlive\":60," "\"cleanSession\":false,\"entityFormat\":1,\"base\":\"ems-esp\",\"discoveryPrefix\":\"homeassistant\",\"discoveryType\":0,\"nestedFormat\":1," "\"haEnabled\":true,\"mqttQos\":0,\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10," "\"publishTimeSolar\":10,\"publishTimeMixer\":10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false," - "\"publish2command\":false,\"sendResponse\":false},\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":3,\"temperatureSensorReads\":0," - "\"temperatureSensorFails\":0,\"analogSensors\":5,\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{" - "\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0," - "\"busReadsFailed\":0,\"busWritesFailed\":0,\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":" - "\"en\",\"txMode\":1,\"emsBusID\":11,\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false," - "\"readonlyMode\":false,\"fahrenheit\":false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true," - "\"telnetEnabled\":true,\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" - "\"boiler\",\"name\":\"My Custom " + "\"publish2command\":false,\"sendResponse\":false},\"syslog\":{\"enabled\":false},\"modbus\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":3," + "\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0," + "\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\"," + "\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0," + "\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11," + "\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":" + "false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true," + "\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My " + "Custom " "Boiler\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":39,\"handlersReceived\":\"0x18\"," "\"handlersFetched\":\"0x14 0x33\",\"handlersPending\":\"0xBF 0x10 0x11 0xC2 0xC6 0x15 0x1C 0x19 0x1A 0x35 0x34 0x2A 0xD1 0xE3 0xE4 0xE5 0xE9 0x02E0 " "0x2E " @@ -278,12 +278,12 @@ void test_25() { auto expected_response = "[{\"api_data\":\"# HELP emsesp_system_uptimesec uptimeSec\\n# TYPE emsesp_system_uptimesec gauge\\nemsesp_system_uptimesec 0\\n# HELP " "emsesp_system_txpause txpause\\n# TYPE emsesp_system_txpause gauge\\nemsesp_system_txpause 0\\n# HELP emsesp_system_info info\\n# TYPE " - "emsesp_system_info gauge\\nemsesp_system_info{version=\\\"dev\\\", resetreason=\\\"Unknown / Unknown\\\", gpios_in_use=\\\"23, 5, 2, 18, 0" - "\\\"} 1\\n# HELP emsesp_network_rssi RSSI\\n# TYPE emsesp_network_rssi gauge\\nemsesp_network_rssi -23\\n# HELP emsesp_network_txpowersetting " - "TxPowerSetting\\n# TYPE emsesp_network_txpowersetting gauge\\nemsesp_network_txpowersetting 0\\n# HELP emsesp_network_staticip staticIP\\n# TYPE " - "emsesp_network_staticip gauge\\nemsesp_network_staticip 0\\n# HELP emsesp_network_lowbandwidth lowBandwidth\\n# TYPE emsesp_network_lowbandwidth " - "gauge\\nemsesp_network_lowbandwidth 0\\n# HELP emsesp_network_disablesleep disableSleep\\n# TYPE emsesp_network_disablesleep " - "gauge\\nemsesp_network_disablesleep 1\\n# HELP emsesp_network_enablemdns enableMDNS\\n# TYPE emsesp_network_enablemdns " + "emsesp_system_info gauge\\nemsesp_system_info{version=\\\"dev\\\", resetreason=\\\"Unknown / Unknown\\\", gpios_allowed=\\\"0, 2, 5, 18, 23\\\", " + "gpios_in_use=\\\"0, 2, 5, 18, 23\\\"} 1\\n# HELP emsesp_network_rssi RSSI\\n# TYPE emsesp_network_rssi gauge\\nemsesp_network_rssi -23\\n# HELP " + "emsesp_network_txpowersetting TxPowerSetting\\n# TYPE emsesp_network_txpowersetting gauge\\nemsesp_network_txpowersetting 0\\n# HELP " + "emsesp_network_staticip staticIP\\n# TYPE emsesp_network_staticip gauge\\nemsesp_network_staticip 0\\n# HELP emsesp_network_lowbandwidth " + "lowBandwidth\\n# TYPE emsesp_network_lowbandwidth gauge\\nemsesp_network_lowbandwidth 0\\n# HELP emsesp_network_disablesleep disableSleep\\n# TYPE " + "emsesp_network_disablesleep gauge\\nemsesp_network_disablesleep 1\\n# HELP emsesp_network_enablemdns enableMDNS\\n# TYPE emsesp_network_enablemdns " "gauge\\nemsesp_network_enablemdns 1\\n# HELP emsesp_network_enablecors enableCORS\\n# TYPE emsesp_network_enablecors " "gauge\\nemsesp_network_enablecors 0\\n# HELP emsesp_network_info info\\n# TYPE emsesp_network_info gauge\\nemsesp_network_info{network=\\\"WiFi\\\", " "hostname=\\\"ems-esp\\\"} 1\\n# HELP emsesp_ntp_enabled enabled\\n# TYPE emsesp_ntp_enabled gauge\\nemsesp_ntp_enabled 1\\n# HELP emsesp_ntp_info " @@ -312,41 +312,43 @@ void test_25() { "emsesp_mqtt_publish2command gauge\\nemsesp_mqtt_publish2command 0\\n# HELP emsesp_mqtt_sendresponse sendResponse\\n# TYPE emsesp_mqtt_sendresponse " "gauge\\nemsesp_mqtt_sendresponse 0\\n# HELP emsesp_mqtt_info info\\n# TYPE emsesp_mqtt_info gauge\\nemsesp_mqtt_info{mqttstatus=\\\"disconnected\\\", " "clientid=\\\"ems-esp\\\", base=\\\"ems-esp\\\", discoveryprefix=\\\"homeassistant\\\"} 1\\n# HELP emsesp_syslog_enabled enabled\\n# TYPE " - "emsesp_syslog_enabled gauge\\nemsesp_syslog_enabled 0\\n# HELP emsesp_sensor_temperaturesensors temperatureSensors\\n# TYPE " - "emsesp_sensor_temperaturesensors gauge\\nemsesp_sensor_temperaturesensors 3\\n# HELP emsesp_sensor_temperaturesensorreads temperatureSensorReads\\n# " - "TYPE emsesp_sensor_temperaturesensorreads gauge\\nemsesp_sensor_temperaturesensorreads 0\\n# HELP emsesp_sensor_temperaturesensorfails " - "temperatureSensorFails\\n# TYPE emsesp_sensor_temperaturesensorfails gauge\\nemsesp_sensor_temperaturesensorfails 0\\n# HELP " - "emsesp_sensor_analogsensors analogSensors\\n# TYPE emsesp_sensor_analogsensors gauge\\nemsesp_sensor_analogsensors 5\\n# HELP " - "emsesp_sensor_analogsensorreads analogSensorReads\\n# TYPE emsesp_sensor_analogsensorreads gauge\\nemsesp_sensor_analogsensorreads 0\\n# HELP " - "emsesp_sensor_analogsensorfails analogSensorFails\\n# TYPE emsesp_sensor_analogsensorfails gauge\\nemsesp_sensor_analogsensorfails 0\\n# HELP " - "emsesp_api_apicalls APICalls\\n# TYPE emsesp_api_apicalls gauge\\nemsesp_api_apicalls 0\\n# HELP emsesp_api_apifails APIFails\\n# TYPE " - "emsesp_api_apifails gauge\\nemsesp_api_apifails 0\\n# HELP emsesp_bus_bustelegramsreceived busTelegramsReceived\\n# TYPE " - "emsesp_bus_bustelegramsreceived gauge\\nemsesp_bus_bustelegramsreceived 8\\n# HELP emsesp_bus_busreads busReads\\n# TYPE emsesp_bus_busreads " - "gauge\\nemsesp_bus_busreads 0\\n# HELP emsesp_bus_buswrites busWrites\\n# TYPE emsesp_bus_buswrites gauge\\nemsesp_bus_buswrites 0\\n# HELP " - "emsesp_bus_busincompletetelegrams busIncompleteTelegrams\\n# TYPE emsesp_bus_busincompletetelegrams gauge\\nemsesp_bus_busincompletetelegrams 0\\n# " - "HELP emsesp_bus_busreadsfailed busReadsFailed\\n# TYPE emsesp_bus_busreadsfailed gauge\\nemsesp_bus_busreadsfailed 0\\n# HELP " - "emsesp_bus_buswritesfailed busWritesFailed\\n# TYPE emsesp_bus_buswritesfailed gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP " - "emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP " - "emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info " - "info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode " - "txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid " - "gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer showerTimer\\n# TYPE emsesp_settings_showertimer " - "gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration showerMinDuration\\n# TYPE emsesp_settings_showerminduration " - "gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert showerAlert\\n# TYPE emsesp_settings_showeralert " - "gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE emsesp_settings_hideled gauge\\nemsesp_settings_hideled 0\\n# " - "HELP emsesp_settings_notokenapi noTokenApi\\n# TYPE emsesp_settings_notokenapi gauge\\nemsesp_settings_notokenapi 0\\n# HELP " - "emsesp_settings_readonlymode readonlyMode\\n# TYPE emsesp_settings_readonlymode gauge\\nemsesp_settings_readonlymode 0\\n# HELP " - "emsesp_settings_fahrenheit fahrenheit\\n# TYPE emsesp_settings_fahrenheit gauge\\nemsesp_settings_fahrenheit 0\\n# HELP " - "emsesp_settings_dallasparasite dallasParasite\\n# TYPE emsesp_settings_dallasparasite gauge\\nemsesp_settings_dallasparasite 0\\n# HELP " - "emsesp_settings_boolformat boolFormat\\n# TYPE emsesp_settings_boolformat gauge\\nemsesp_settings_boolformat 1\\n# HELP emsesp_settings_booldashboard " - "boolDashboard\\n# TYPE emsesp_settings_booldashboard gauge\\nemsesp_settings_booldashboard 1\\n# HELP emsesp_settings_enumformat enumFormat\\n# TYPE " - "emsesp_settings_enumformat gauge\\nemsesp_settings_enumformat 1\\n# HELP emsesp_settings_analogenabled analogEnabled\\n# TYPE " - "emsesp_settings_analogenabled gauge\\nemsesp_settings_analogenabled 1\\n# HELP emsesp_settings_telnetenabled telnetEnabled\\n# TYPE " - "emsesp_settings_telnetenabled gauge\\nemsesp_settings_telnetenabled 1\\n# HELP emsesp_settings_maxweblogbuffer maxWebLogBuffer\\n# TYPE " - "emsesp_settings_maxweblogbuffer gauge\\nemsesp_settings_maxweblogbuffer 25\\n# HELP emsesp_settings_modbusenabled modbusEnabled\\n# TYPE " - "emsesp_settings_modbusenabled gauge\\nemsesp_settings_modbusenabled 0\\n# HELP emsesp_settings_forceheatingoff forceHeatingOff\\n# TYPE " - "emsesp_settings_forceheatingoff gauge\\nemsesp_settings_forceheatingoff 0\\n# HELP emsesp_settings_developermode developerMode\\n# TYPE " - "emsesp_settings_developermode gauge\\nemsesp_settings_developermode 0\\n# HELP emsesp_settings_info info\\n# TYPE emsesp_settings_info " + "emsesp_syslog_enabled gauge\\nemsesp_syslog_enabled 0\\n# HELP emsesp_modbus_enabled enabled\\n# TYPE emsesp_modbus_enabled " + "gauge\\nemsesp_modbus_enabled 0\\n# HELP emsesp_sensor_temperaturesensors temperatureSensors\\n# TYPE emsesp_sensor_temperaturesensors " + "gauge\\nemsesp_sensor_temperaturesensors 3\\n# HELP emsesp_sensor_temperaturesensorreads temperatureSensorReads\\n# TYPE " + "emsesp_sensor_temperaturesensorreads gauge\\nemsesp_sensor_temperaturesensorreads 0\\n# HELP emsesp_sensor_temperaturesensorfails " + "temperatureSensorFails\\n# TYPE emsesp_sensor_temperaturesensorfails gauge\\nemsesp_sensor_temperaturesensorfails 0\\n# HELP emsesp_analog_enabled " + "enabled\\n# TYPE emsesp_analog_enabled gauge\\nemsesp_analog_enabled 1\\n# HELP emsesp_analog_analogsensors analogSensors\\n# TYPE " + "emsesp_analog_analogsensors gauge\\nemsesp_analog_analogsensors 5\\n# HELP emsesp_analog_analogsensorreads analogSensorReads\\n# TYPE " + "emsesp_analog_analogsensorreads gauge\\nemsesp_analog_analogsensorreads 0\\n# HELP emsesp_analog_analogsensorfails analogSensorFails\\n# TYPE " + "emsesp_analog_analogsensorfails gauge\\nemsesp_analog_analogsensorfails 0\\n# HELP emsesp_api_apicalls APICalls\\n# TYPE emsesp_api_apicalls " + "gauge\\nemsesp_api_apicalls 0\\n# HELP emsesp_api_apifails APIFails\\n# TYPE emsesp_api_apifails gauge\\nemsesp_api_apifails 0\\n# HELP " + "emsesp_bus_bustelegramsreceived busTelegramsReceived\\n# TYPE emsesp_bus_bustelegramsreceived gauge\\nemsesp_bus_bustelegramsreceived 8\\n# HELP " + "emsesp_bus_busreads busReads\\n# TYPE emsesp_bus_busreads gauge\\nemsesp_bus_busreads 0\\n# HELP emsesp_bus_buswrites busWrites\\n# TYPE " + "emsesp_bus_buswrites gauge\\nemsesp_bus_buswrites 0\\n# HELP emsesp_bus_busincompletetelegrams busIncompleteTelegrams\\n# TYPE " + "emsesp_bus_busincompletetelegrams gauge\\nemsesp_bus_busincompletetelegrams 0\\n# HELP emsesp_bus_busreadsfailed busReadsFailed\\n# TYPE " + "emsesp_bus_busreadsfailed gauge\\nemsesp_bus_busreadsfailed 0\\n# HELP emsesp_bus_buswritesfailed busWritesFailed\\n# TYPE emsesp_bus_buswritesfailed " + "gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality " + "gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality " + "gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", " + "busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP " + "emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer " + "showerTimer\\n# TYPE emsesp_settings_showertimer gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration " + "showerMinDuration\\n# TYPE emsesp_settings_showerminduration gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert " + "showerAlert\\n# TYPE emsesp_settings_showeralert gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE " + "emsesp_settings_hideled gauge\\nemsesp_settings_hideled 0\\n# HELP emsesp_settings_notokenapi noTokenApi\\n# TYPE emsesp_settings_notokenapi " + "gauge\\nemsesp_settings_notokenapi 0\\n# HELP emsesp_settings_readonlymode readonlyMode\\n# TYPE emsesp_settings_readonlymode " + "gauge\\nemsesp_settings_readonlymode 0\\n# HELP emsesp_settings_fahrenheit fahrenheit\\n# TYPE emsesp_settings_fahrenheit " + "gauge\\nemsesp_settings_fahrenheit 0\\n# HELP emsesp_settings_dallasparasite dallasParasite\\n# TYPE emsesp_settings_dallasparasite " + "gauge\\nemsesp_settings_dallasparasite 0\\n# HELP emsesp_settings_boolformat boolFormat\\n# TYPE emsesp_settings_boolformat " + "gauge\\nemsesp_settings_boolformat 1\\n# HELP emsesp_settings_booldashboard boolDashboard\\n# TYPE emsesp_settings_booldashboard " + "gauge\\nemsesp_settings_booldashboard 1\\n# HELP emsesp_settings_enumformat enumFormat\\n# TYPE emsesp_settings_enumformat " + "gauge\\nemsesp_settings_enumformat 1\\n# HELP emsesp_settings_analogenabled analogEnabled\\n# TYPE emsesp_settings_analogenabled " + "gauge\\nemsesp_settings_analogenabled 1\\n# HELP emsesp_settings_telnetenabled telnetEnabled\\n# TYPE emsesp_settings_telnetenabled " + "gauge\\nemsesp_settings_telnetenabled 1\\n# HELP emsesp_settings_maxweblogbuffer maxWebLogBuffer\\n# TYPE emsesp_settings_maxweblogbuffer " + "gauge\\nemsesp_settings_maxweblogbuffer 25\\n# HELP emsesp_settings_modbusenabled modbusEnabled\\n# TYPE emsesp_settings_modbusenabled " + "gauge\\nemsesp_settings_modbusenabled 0\\n# HELP emsesp_settings_forceheatingoff forceHeatingOff\\n# TYPE emsesp_settings_forceheatingoff " + "gauge\\nemsesp_settings_forceheatingoff 0\\n# HELP emsesp_settings_developermode developerMode\\n# TYPE emsesp_settings_developermode " + "gauge\\nemsesp_settings_developermode 0\\n# HELP emsesp_settings_info info\\n# TYPE emsesp_settings_info " "gauge\\nemsesp_settings_info{boardprofile=\\\"S32\\\", locale=\\\"en\\\"} 1\\n# HELP emsesp_device_productid productID\\n# TYPE " "emsesp_device_productid gauge\\nemsesp_device_productid{type=\\\"boiler\\\", name=\\\"My Custom Boiler\\\", deviceid=\\\"0x08\\\", " "version=\\\"01.00\\\"} 123\\n# HELP emsesp_device_entities entities\\n# TYPE emsesp_device_entities " diff --git a/test/test_data/custom_support.json b/test/test_data/custom_support.json index b528645a3..6d5b81502 100644 --- a/test/test_data/custom_support.json +++ b/test/test_data/custom_support.json @@ -13,6 +13,6 @@ "", "For help and questions please contact your installer." ], - "img_url": "https://emsesp.org/_media/images/designer.png" + "img_url": "https://emsesp.org/media/images/designer.png" } } \ No newline at end of file diff --git a/test/test_data/emsesp_allvalues.json b/test/test_data/emsesp_allvalues.json new file mode 100644 index 000000000..6a8297eb1 --- /dev/null +++ b/test/test_data/emsesp_allvalues.json @@ -0,0 +1,103 @@ +{ + "Boiler Nefit Trendline HRC30 (DeviceID:0x08, ProductID:123, Version:06.01)": { + "force heating off": "off", + "heating active": "off", + "tapwater active": "off", + "selected flow temperature": 5, + "heating pump modulation": 0, + "current flow temperature": 41.4, + "return temperature": 37.7, + "system pressure": 1.3, + "actual boiler temperature": 44.2, + "gas": "off", + "gas stage 2": "off", + "flame current": 0, + "fan": "off", + "ignition": "off", + "oil preheating": "off", + "burner min power": 0, + "burner max power": 50, + "burner min period": 10, + "hysteresis on temperature": -6, + "hysteresis off temperature": 6, + "heating activated": "on", + "heating temperature": 70, + "heating pump": "off", + "boiler pump max power": 70, + "boiler pump min power": 50, + "boiler pump mode": "proportional", + "pump delay": 2, + "burner selected max power": 0, + "burner current power": 0, + "burner starts": 394602, + "total burner operating time": "480 days 4 hours 23 minutes", + "burner stage 2 operating time": "0 days 0 hours 0 minutes", + "total heat operating time": "395 days 2 hours 14 minutes", + "burner starts heating": 46245, + "total UBA operating time": "3932 days 23 hours 58 minutes", + "last error code": "2E(207) 100.75.2000 65:00 (0 min)", + "service code": "0H", + "service code number": 203, + "maintenance message": "H00", + "maintenance scheduled": "manual", + "time to next maintenance": 6000, + "next maintenance date": "01.01.2012", + "dhw turn on/off": "on", + "dhw set temperature": 62, + "dhw selected temperature": 60, + "dhw type": "flow", + "dhw comfort": "hot", + "dhw flow temperature offset": 40, + "dhw max power": 100, + "dhw circulation pump available": "off", + "dhw charging type": "3-way valve", + "dhw hysteresis on temperature": -5, + "dhw hysteresis off temperature": 0, + "dhw disinfection temperature": 70, + "dhw circulation pump mode": "off", + "dhw circulation active": "off", + "dhw current intern temperature": 33.5, + "dhw current tap water flow": 0, + "dhw storage intern temperature": 33.5, + "dhw activated": "on", + "dhw one time charging": "off", + "dhw disinfecting": "off", + "dhw charging": "off", + "dhw recharging": "off", + "dhw temperature ok": "on", + "dhw active": "off", + "dhw 3-way valve active": "on", + "dhw set pump power": 0, + "dhw starts": 348357, + "dhw active time": "85 days 2 hours 9 minutes", + "nominal Power": 30, + "total energy": 3088.69, + "energy heating": 2532.94, + "dhw energy": 555.75 + }, + "Thermostat RC20 (DeviceID:0x17, ProductID:77, Version:03.03)": { + "date/time": "10.12.2023 13:49", + "hc1 how hot lounge should be": 19, + "hc1 current room temp": 19.5, + "hc1 mqtt discovery current room temperature": "roomTemp", + "hc1 mode": "auto", + "hc1 manual temperature": 21.5, + "hc1 temperature when mode is off": 7, + "hc1 day temperature T2": 20, + "hc1 day temperature T3": 20, + "hc1 day temperature T4": 20, + "hc1 night temperature T1": 15, + "hc1 program switchtime": "00 mo 00:00 T1" + }, + "Controller Module BC10 (DeviceID:0x09, ProductID:190, Version:01.03)": {}, + "Custom Entities": { + "boiler_flowtemp": 5, + "nominalpower": 30, + "minmodulation": 23, + "maxmodulation": 115 + }, + "Analog Sensors": {}, + "Temperature Sensors": { + "zolder": 18.3 + } +} \ No newline at end of file diff --git a/test/test_data/emsesp_customizations.json b/test/test_data/emsesp_customizations.json new file mode 100644 index 000000000..99ba91cef --- /dev/null +++ b/test/test_data/emsesp_customizations.json @@ -0,0 +1,37 @@ +{ + "type": "customizations", + "Customizations": { + "ts": [], + "as": [], + "masked_entities": [ + { + "product_id": 77, + "device_id": 23, + "custom_name": "", + "custom_brand": "", + "entity_ids": [ + "08datetime", + "08hc1/seltemp|<30", + "08hc1/currtemp", + "08hc1/mode" + ] + }, + { + "product_id": 123, + "device_id": 8, + "custom_name": "", + "custom_brand": "", + "entity_ids": [ + "08heatingactive", + "08burngas", + "08fanwork", + "08ignwork", + "08burnmaxpower|>23<121", + "08burnminperiod|<120", + "08lastcode", + "08servicecode" + ] + } + ] + } +} \ No newline at end of file diff --git a/test/test_data/emsesp_entities.json b/test/test_data/emsesp_entities.json new file mode 100644 index 000000000..804cc81d4 --- /dev/null +++ b/test/test_data/emsesp_entities.json @@ -0,0 +1,6 @@ +{ + "type": "entities", + "Entities": { + "entities": [] + } +} \ No newline at end of file diff --git a/test/test_data/emsesp_schedule.json b/test/test_data/emsesp_schedule.json new file mode 100644 index 000000000..8674b3959 --- /dev/null +++ b/test/test_data/emsesp_schedule.json @@ -0,0 +1,6 @@ +{ + "type": "schedule", + "Schedule": { + "schedule": [] + } +} \ No newline at end of file diff --git a/test/test_data/emsesp_settings.json b/test/test_data/emsesp_settings.json new file mode 100644 index 000000000..80b8f74d4 --- /dev/null +++ b/test/test_data/emsesp_settings.json @@ -0,0 +1,145 @@ +{ + "type": "settings", + "System": { + "version": "3.8.2" + }, + "Network": { + "ssid": "", + "bssid": "", + "password": "", + "hostname": "ems-esp", + "static_ip_config": false, + "bandwidth20": false, + "nosleep": true, + "enableMDNS": true, + "enableCORS": false, + "CORSOrigin": "*", + "tx_power": 0 + }, + "AP": { + "provision_mode": 2, + "ssid": "ems-esp", + "password": "ems-esp-neo", + "channel": 1, + "ssid_hidden": false, + "max_clients": 4, + "local_ip": "192.168.4.1", + "gateway_ip": "192.168.4.1", + "subnet_mask": "255.255.255.0" + }, + "MQTT": { + "enableTLS": false, + "rootCA": "", + "enabled": true, + "host": "192.168.X.X", + "port": 1883, + "base": "ems-esp", + "username": "xxxx", + "password": "xxxx", + "client_id": "esp32-395c7bcc", + "keep_alive": 60, + "clean_session": false, + "entity_format": 1, + "publish_time_boiler": 60, + "publish_time_thermostat": 60, + "publish_time_solar": 60, + "publish_time_mixer": 60, + "publish_time_water": 60, + "publish_time_other": 60, + "publish_time_sensor": 60, + "publish_time_heartbeat": 10, + "mqtt_qos": 0, + "mqtt_retain": false, + "ha_enabled": true, + "nested_format": 1, + "discovery_prefix": "homeassistant", + "discovery_type": 0, + "ha_number_mode": 1, + "publish_single": false, + "publish_single2cmd": false, + "send_response": false + }, + "NTP": { + "enabled": true, + "server": "time.google.com", + "tz_label": "Europe/Amsterdam", + "tz_format": "CET-1CEST,M3.5.0,M10.5.0/3" + }, + "Security": { + "jwt_secret": "ems-esp-neo", + "users": [ + { + "username": "admin", + "password": "admin", + "admin": true + }, + { + "username": "guest", + "password": "guest", + "admin": false + } + ] + }, + "Settings": { + "version": "3.8.2", + "board_profile": "E32V2", + "platform": "ESP32", + "locale": "en", + "tx_mode": 1, + "ems_bus_id": 11, + "syslog_enabled": false, + "syslog_level": 3, + "trace_raw": false, + "syslog_mark_interval": 0, + "syslog_host": "", + "syslog_port": 514, + "boiler_heatingoff": false, + "remote_timeout": 24, + "remote_timeout_en": false, + "shower_timer": true, + "shower_alert": false, + "shower_alert_coldshot": 10, + "shower_alert_trigger": 7, + "shower_min_duration": 180, + "rx_gpio": 4, + "tx_gpio": 5, + "dallas_gpio": 14, + "dallas_parasite": false, + "led_gpio": 2, + "hide_led": true, + "led_type": 0, + "low_clock": false, + "telnet_enabled": true, + "notoken_api": false, + "readonly_mode": false, + "analog_enabled": true, + "pbutton_gpio": 34, + "solar_maxflow": 30, + "fahrenheit": false, + "bool_format": 1, + "bool_dashboard": 1, + "enum_format": 1, + "weblog_level": 6, + "weblog_buffer": 500, + "weblog_compact": true, + "phy_type": 1, + "eth_power": 15, + "eth_phy_addr": 0, + "eth_clock_mode": 1, + "modbus_enabled": false, + "modbus_port": 502, + "modbus_max_clients": 10, + "modbus_timeout": 300, + "developer_mode": true, + "email_enabled": false, + "email_ssl": false, + "email_starttls": true, + "email_server": "smtp.example.net", + "email_port": 587, + "email_login": "", + "email_pass": "", + "email_sender": "ems-esp@example.net", + "email_recp": "", + "email_subject": "ems-esp notification" + } +} \ No newline at end of file diff --git a/test/test_data/emsesp_systembackup.json b/test/test_data/emsesp_systembackup.json new file mode 100644 index 000000000..3f7b0816c --- /dev/null +++ b/test/test_data/emsesp_systembackup.json @@ -0,0 +1,249 @@ +{ + "type": "systembackup", + "version": "3.8.2", + "date": "2026-04-15T08:06:45", + "systembackup": [ + { + "type": "settings", + "Network": { + "ssid": "", + "bssid": "", + "password": "", + "hostname": "ems-esp", + "static_ip_config": false, + "bandwidth20": false, + "nosleep": true, + "enableMDNS": true, + "enableCORS": false, + "CORSOrigin": "*", + "tx_power": 0 + }, + "AP": { + "provision_mode": 2, + "ssid": "ems-esp", + "password": "ems-esp-neo", + "channel": 1, + "ssid_hidden": false, + "max_clients": 4, + "local_ip": "192.168.X.X", + "gateway_ip": "192.168.X.X", + "subnet_mask": "255.255.255.0" + }, + "MQTT": { + "enableTLS": false, + "rootCA": "", + "enabled": true, + "host": "192.168.X.X", + "port": 1883, + "base": "ems-esp", + "username": "xxxx", + "password": "xxxx", + "client_id": "esp32-395c7bcc", + "keep_alive": 60, + "clean_session": false, + "entity_format": 1, + "publish_time_boiler": 60, + "publish_time_thermostat": 60, + "publish_time_solar": 60, + "publish_time_mixer": 60, + "publish_time_water": 60, + "publish_time_other": 60, + "publish_time_sensor": 60, + "publish_time_heartbeat": 10, + "mqtt_qos": 0, + "mqtt_retain": false, + "ha_enabled": true, + "nested_format": 1, + "discovery_prefix": "homeassistant", + "discovery_type": 0, + "ha_number_mode": 1, + "publish_single": false, + "publish_single2cmd": false, + "send_response": false + }, + "NTP": { + "enabled": true, + "server": "time.google.com", + "tz_label": "Europe/Amsterdam", + "tz_format": "CET-1CEST,M3.5.0,M10.5.0/3" + }, + "Security": { + "jwt_secret": "ems-esp-neo", + "users": [ + { + "username": "admin", + "password": "admin", + "admin": true + }, + { + "username": "guest", + "password": "guest", + "admin": false + } + ] + }, + "Settings": { + "version": "3.8.2", + "board_profile": "E32V2", + "platform": "ESP32", + "locale": "en", + "tx_mode": 1, + "ems_bus_id": 11, + "syslog_enabled": false, + "syslog_level": 3, + "trace_raw": false, + "syslog_mark_interval": 0, + "syslog_host": "", + "syslog_port": 514, + "boiler_heatingoff": false, + "remote_timeout": 24, + "remote_timeout_en": false, + "shower_timer": true, + "shower_alert": false, + "shower_alert_coldshot": 10, + "shower_alert_trigger": 7, + "shower_min_duration": 180, + "rx_gpio": 4, + "tx_gpio": 5, + "dallas_gpio": 14, + "dallas_parasite": false, + "led_gpio": 2, + "hide_led": true, + "led_type": 0, + "low_clock": false, + "telnet_enabled": true, + "notoken_api": false, + "readonly_mode": false, + "analog_enabled": true, + "pbutton_gpio": 34, + "solar_maxflow": 30, + "fahrenheit": false, + "bool_format": 1, + "bool_dashboard": 1, + "enum_format": 1, + "weblog_level": 6, + "weblog_buffer": 75, + "weblog_compact": true, + "phy_type": 1, + "eth_power": 15, + "eth_phy_addr": 0, + "eth_clock_mode": 1, + "modbus_enabled": false, + "modbus_port": 502, + "modbus_max_clients": 10, + "modbus_timeout": 300, + "developer_mode": true + } + }, + { + "type": "schedule", + "Schedule": { + "schedule": [] + } + }, + { + "type": "customizations", + "Customizations": { + "ts": [], + "as": [], + "masked_entities": [ + { + "product_id": 77, + "device_id": 23, + "custom_name": "", + "custom_brand": "", + "entity_ids": [ + "08datetime", + "08hc1/seltemp|<30", + "08hc1/currtemp", + "08hc1/mode" + ] + }, + { + "product_id": 123, + "device_id": 8, + "custom_name": "", + "custom_brand": "", + "entity_ids": [ + "08heatingactive", + "08burngas", + "08fanwork", + "08ignwork", + "08burnmaxpower|>23<121", + "08burnminperiod|<120", + "08lastcode", + "08servicecode" + ] + } + ] + } + }, + { + "type": "entities", + "Entities": { + "entities": [] + } + }, + { + "type": "modules", + "Modules": { + "modules": [] + } + }, + { + "type": "nvs", + "nvs": [ + { + "type": 1, + "key": "nompower", + "value": 30 + }, + { + "type": 33, + "key": "boot", + "value": "3.8.1-dev.4" + }, + { + "type": 4, + "key": "d_boot", + "value": 1767525325 + }, + { + "type": 33, + "key": "app1", + "value": "3.8.2-dev.13" + }, + { + "type": 33, + "key": "app0", + "value": "3.8.1" + }, + { + "type": 4, + "key": "d_app0", + "value": 1774988066 + }, + { + "type": 1, + "key": "fresh_firmware", + "value": 0 + }, + { + "type": 4, + "key": "d_app1", + "value": 1776194060 + }, + { + "type": 66, + "key": "nrgheat", + "value": 485871.5481 + }, + { + "type": 66, + "key": "nrgww", + "value": 101649.2176 + } + ] + } + ] +} \ No newline at end of file