Merge pull request #2729 from proddy/dev

web UI improvements and more fixes for system sensors
This commit is contained in:
Proddy
2025-11-10 22:38:04 +01:00
committed by GitHub
31 changed files with 489 additions and 491 deletions

View File

@@ -30,6 +30,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
- RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659)
- new boiler entities VR0,VR1, compressor speed [#2669](https://github.com/emsesp/EMS-ESP32/issues/2669)
- solar temperature TS16 [#2690](https://github.com/emsesp/EMS-ESP32/issues/2690)
- pumpmode enum for HT3 boilers, add commands for manual defrost, chimneysweeper [#2727](https://github.com/emsesp/EMS-ESP32/issues/2727)
## Fixed

View File

@@ -62,10 +62,10 @@
"prettier": "^3.6.2",
"rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.44.1",
"typescript-eslint": "^8.46.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.2",
"vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.1.4"
},
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
"packageManager": "pnpm@10.21.0+sha512.da3337267e400fdd3d479a6c68079ac6db01d8ca4f67572083e722775a796788a7a9956613749e000fac20d424b594f7a791a5f4e2e13581c5ef947f26968a40"
}

326
interface/pnpm-lock.yaml generated
View File

@@ -113,13 +113,13 @@ importers:
version: 3.6.2
rollup-plugin-visualizer:
specifier: ^6.0.5
version: 6.0.5(rollup@4.53.1)
version: 6.0.5(rollup@4.53.2)
terser:
specifier: ^5.44.1
version: 5.44.1
typescript-eslint:
specifier: ^8.46.3
version: 8.46.3(eslint@9.39.1)(typescript@5.9.3)
specifier: ^8.46.4
version: 8.46.4(eslint@9.39.1)(typescript@5.9.3)
vite:
specifier: ^7.2.2
version: 7.2.2(@types/node@24.10.0)(terser@5.44.1)
@@ -661,8 +661,8 @@ packages:
'@prefresh/babel-plugin@0.5.2':
resolution: {integrity: sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA==}
'@prefresh/core@1.5.8':
resolution: {integrity: sha512-T7HMpakS1iPVCFZvfDLMGyrWAcO3toUN9/RkJUqqoRr/vNhQrZgHjidfhq3awDzAQtw1emDWH8dsOeu0DWqtgA==}
'@prefresh/core@1.5.9':
resolution: {integrity: sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==}
peerDependencies:
preact: ^10.0.0 || ^11.0.0-0
@@ -679,113 +679,113 @@ packages:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'}
'@rollup/rollup-android-arm-eabi@4.53.1':
resolution: {integrity: sha512-bxZtughE4VNVJlL1RdoSE545kc4JxL7op57KKoi59/gwuU5rV6jLWFXXc8jwgFoT6vtj+ZjO+Z2C5nrY0Cl6wA==}
'@rollup/rollup-android-arm-eabi@4.53.2':
resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.53.1':
resolution: {integrity: sha512-44a1hreb02cAAfAKmZfXVercPFaDjqXCK+iKeVOlJ9ltvnO6QqsBHgKVPTu+MJHSLLeMEUbeG2qiDYgbFPU48g==}
'@rollup/rollup-android-arm64@4.53.2':
resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.53.1':
resolution: {integrity: sha512-usmzIgD0rf1syoOZ2WZvy8YpXK5G1V3btm3QZddoGSa6mOgfXWkkv+642bfUUldomgrbiLQGrPryb7DXLovPWQ==}
'@rollup/rollup-darwin-arm64@4.53.2':
resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.53.1':
resolution: {integrity: sha512-is3r/k4vig2Gt8mKtTlzzyaSQ+hd87kDxiN3uDSDwggJLUV56Umli6OoL+/YZa/KvtdrdyNfMKHzL/P4siOOmg==}
'@rollup/rollup-darwin-x64@4.53.2':
resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.53.1':
resolution: {integrity: sha512-QJ1ksgp/bDJkZB4daldVmHaEQkG4r8PUXitCOC2WRmRaSaHx5RwPoI3DHVfXKwDkB+Sk6auFI/+JHacTekPRSw==}
'@rollup/rollup-freebsd-arm64@4.53.2':
resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.53.1':
resolution: {integrity: sha512-J6ma5xgAzvqsnU6a0+jgGX/gvoGokqpkx6zY4cWizRrm0ffhHDpJKQgC8dtDb3+MqfZDIqs64REbfHDMzxLMqQ==}
'@rollup/rollup-freebsd-x64@4.53.2':
resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.53.1':
resolution: {integrity: sha512-JzWRR41o2U3/KMNKRuZNsDUAcAVUYhsPuMlx5RUldw0E4lvSIXFUwejtYz1HJXohUmqs/M6BBJAUBzKXZVddbg==}
'@rollup/rollup-linux-arm-gnueabihf@4.53.2':
resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.53.1':
resolution: {integrity: sha512-L8kRIrnfMrEoHLHtHn+4uYA52fiLDEDyezgxZtGUTiII/yb04Krq+vk3P2Try+Vya9LeCE9ZHU8CXD6J9EhzHQ==}
'@rollup/rollup-linux-arm-musleabihf@4.53.2':
resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.53.1':
resolution: {integrity: sha512-ysAc0MFRV+WtQ8li8hi3EoFi7us6d1UzaS/+Dp7FYZfg3NdDljGMoVyiIp6Ucz7uhlYDBZ/zt6XI0YEZbUO11Q==}
'@rollup/rollup-linux-arm64-gnu@4.53.2':
resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-arm64-musl@4.53.1':
resolution: {integrity: sha512-UV6l9MJpDbDZZ/fJvqNcvO1PcivGEf1AvKuTcHoLjVZVFeAMygnamCTDikCVMRnA+qJe+B3pSbgX2+lBMqgBhA==}
'@rollup/rollup-linux-arm64-musl@4.53.2':
resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-loong64-gnu@4.53.1':
resolution: {integrity: sha512-UDUtelEprkA85g95Q+nj3Xf0M4hHa4DiJ+3P3h4BuGliY4NReYYqwlc0Y8ICLjN4+uIgCEvaygYlpf0hUj90Yg==}
'@rollup/rollup-linux-loong64-gnu@4.53.2':
resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==}
cpu: [loong64]
os: [linux]
'@rollup/rollup-linux-ppc64-gnu@4.53.1':
resolution: {integrity: sha512-vrRn+BYhEtNOte/zbc2wAUQReJXxEx2URfTol6OEfY2zFEUK92pkFBSXRylDM7aHi+YqEPJt9/ABYzmcrS4SgQ==}
'@rollup/rollup-linux-ppc64-gnu@4.53.2':
resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.53.1':
resolution: {integrity: sha512-gto/1CxHyi4A7YqZZNznQYrVlPSaodOBPKM+6xcDSCMVZN/Fzb4K+AIkNz/1yAYz9h3Ng+e2fY9H6bgawVq17w==}
'@rollup/rollup-linux-riscv64-gnu@4.53.2':
resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.53.1':
resolution: {integrity: sha512-KZ6Vx7jAw3aLNjFR8eYVcQVdFa/cvBzDNRFM3z7XhNNunWjA03eUrEwJYPk0G8V7Gs08IThFKcAPS4WY/ybIrQ==}
'@rollup/rollup-linux-riscv64-musl@4.53.2':
resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.53.1':
resolution: {integrity: sha512-HvEixy2s/rWNgpwyKpXJcHmE7om1M89hxBTBi9Fs6zVuLU4gOrEMQNbNsN/tBVIMbLyysz/iwNiGtMOpLAOlvA==}
'@rollup/rollup-linux-s390x-gnu@4.53.2':
resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==}
cpu: [s390x]
os: [linux]
'@rollup/rollup-linux-x64-gnu@4.53.1':
resolution: {integrity: sha512-E/n8x2MSjAQgjj9IixO4UeEUeqXLtiA7pyoXCFYLuXpBA/t2hnbIdxHfA7kK9BFsYAoNU4st1rHYdldl8dTqGA==}
'@rollup/rollup-linux-x64-gnu@4.53.2':
resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==}
cpu: [x64]
os: [linux]
'@rollup/rollup-linux-x64-musl@4.53.1':
resolution: {integrity: sha512-IhJ087PbLOQXCN6Ui/3FUkI9pWNZe/Z7rEIVOzMsOs1/HSAECCvSZ7PkIbkNqL/AZn6WbZvnoVZw/qwqYMo4/w==}
'@rollup/rollup-linux-x64-musl@4.53.2':
resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==}
cpu: [x64]
os: [linux]
'@rollup/rollup-openharmony-arm64@4.53.1':
resolution: {integrity: sha512-0++oPNgLJHBblreu0SFM7b3mAsBJBTY0Ksrmu9N6ZVrPiTkRgda52mWR7TKhHAsUb9noCjFvAw9l6ZO1yzaVbA==}
'@rollup/rollup-openharmony-arm64@4.53.2':
resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.53.1':
resolution: {integrity: sha512-VJXivz61c5uVdbmitLkDlbcTk9Or43YC2QVLRkqp86QoeFSqI81bNgjhttqhKNMKnQMWnecOCm7lZz4s+WLGpQ==}
'@rollup/rollup-win32-arm64-msvc@4.53.2':
resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.53.1':
resolution: {integrity: sha512-NmZPVTUOitCXUH6erJDzTQ/jotYw4CnkMDjCYRxNHVD9bNyfrGoIse684F9okwzKCV4AIHRbUkeTBc9F2OOH5Q==}
'@rollup/rollup-win32-ia32-msvc@4.53.2':
resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-gnu@4.53.1':
resolution: {integrity: sha512-2SNj7COIdAf6yliSpLdLG8BEsp5lgzRehgfkP0Av8zKfQFKku6JcvbobvHASPJu4f3BFxej5g+HuQPvqPhHvpQ==}
'@rollup/rollup-win32-x64-gnu@4.53.2':
resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.53.1':
resolution: {integrity: sha512-rLarc1Ofcs3DHtgSzFO31pZsCh8g05R2azN1q3fF+H423Co87My0R+tazOEvYVKXSLh8C4LerMK41/K7wlklcg==}
'@rollup/rollup-win32-x64-msvc@4.53.2':
resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==}
cpu: [x64]
os: [win32]
@@ -888,63 +888,63 @@ packages:
'@types/svgo@2.6.4':
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
'@typescript-eslint/eslint-plugin@8.46.3':
resolution: {integrity: sha512-sbaQ27XBUopBkRiuY/P9sWGOWUW4rl8fDoHIUmLpZd8uldsTyB4/Zg6bWTegPoTLnKj9Hqgn3QD6cjPNB32Odw==}
'@typescript-eslint/eslint-plugin@8.46.4':
resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.46.3
'@typescript-eslint/parser': ^8.46.4
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/parser@8.46.3':
resolution: {integrity: sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==}
'@typescript-eslint/parser@8.46.4':
resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.46.3':
resolution: {integrity: sha512-Fz8yFXsp2wDFeUElO88S9n4w1I4CWDTXDqDr9gYvZgUpwXQqmZBr9+NTTql5R3J7+hrJZPdpiWaB9VNhAKYLuQ==}
'@typescript-eslint/project-service@8.46.4':
resolution: {integrity: sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.46.3':
resolution: {integrity: sha512-FCi7Y1zgrmxp3DfWfr+3m9ansUUFoy8dkEdeQSgA9gbm8DaHYvZCdkFRQrtKiedFf3Ha6VmoqoAaP68+i+22kg==}
'@typescript-eslint/scope-manager@8.46.4':
resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.46.3':
resolution: {integrity: sha512-GLupljMniHNIROP0zE7nCcybptolcH8QZfXOpCfhQDAdwJ/ZTlcaBOYebSOZotpti/3HrHSw7D3PZm75gYFsOA==}
'@typescript-eslint/tsconfig-utils@8.46.4':
resolution: {integrity: sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/type-utils@8.46.3':
resolution: {integrity: sha512-ZPCADbr+qfz3aiTTYNNkCbUt+cjNwI/5McyANNrFBpVxPt7GqpEYz5ZfdwuFyGUnJ9FdDXbGODUu6iRCI6XRXw==}
'@typescript-eslint/type-utils@8.46.4':
resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.46.3':
resolution: {integrity: sha512-G7Ok9WN/ggW7e/tOf8TQYMaxgID3Iujn231hfi0Pc7ZheztIJVpO44ekY00b7akqc6nZcvregk0Jpah3kep6hA==}
'@typescript-eslint/types@8.46.4':
resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.46.3':
resolution: {integrity: sha512-f/NvtRjOm80BtNM5OQtlaBdM5BRFUv7gf381j9wygDNL+qOYSNOgtQ/DCndiYi80iIOv76QqaTmp4fa9hwI0OA==}
'@typescript-eslint/typescript-estree@8.46.4':
resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.46.3':
resolution: {integrity: sha512-VXw7qmdkucEx9WkmR3ld/u6VhRyKeiF1uxWwCy/iuNfokjJ7VhsgLSOTjsol8BunSw190zABzpwdNsze2Kpo4g==}
'@typescript-eslint/utils@8.46.4':
resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.46.3':
resolution: {integrity: sha512-uk574k8IU0rOF/AjniX8qbLSGURJVUCeM5e4MIMKBFFi8weeiLrG1fyQejyLXQpRZbU/1BuQasleV/RfHC3hHg==}
'@typescript-eslint/visitor-keys@8.46.4':
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2:
@@ -2628,8 +2628,8 @@ packages:
rollup:
optional: true
rollup@4.53.1:
resolution: {integrity: sha512-n2I0V0lN3E9cxxMqBCT3opWOiQBzRN7UG60z/WDKqdX2zHUS/39lezBcsckZFsV6fUTSnfqI7kHf60jDAPGKug==}
rollup@4.53.2:
resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -2927,8 +2927,8 @@ packages:
peerDependencies:
typescript: '>=3.5.1'
typescript-eslint@8.46.3:
resolution: {integrity: sha512-bAfgMavTuGo+8n6/QQDVQz4tZ4f7Soqg53RbrlZQEoAltYop/XR4RAts/I0BrO3TTClTSTFJ0wYbla+P8cEWJA==}
typescript-eslint@8.46.4:
resolution: {integrity: sha512-KALyxkpYV5Ix7UhvjTwJXZv76VWsHG+NjNlt/z+a17SOQSiOcBdUXdbJdyXi7RPxrBFECtFOiPwUJQusJuCqrg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -3616,7 +3616,7 @@ snapshots:
'@prefresh/babel-plugin@0.5.2': {}
'@prefresh/core@1.5.8(preact@10.27.2)':
'@prefresh/core@1.5.9(preact@10.27.2)':
dependencies:
preact: 10.27.2
@@ -3626,7 +3626,7 @@ snapshots:
dependencies:
'@babel/core': 7.28.5
'@prefresh/babel-plugin': 0.5.2
'@prefresh/core': 1.5.8(preact@10.27.2)
'@prefresh/core': 1.5.9(preact@10.27.2)
'@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1
preact: 10.27.2
@@ -3639,70 +3639,70 @@ snapshots:
estree-walker: 2.0.2
picomatch: 2.3.1
'@rollup/rollup-android-arm-eabi@4.53.1':
'@rollup/rollup-android-arm-eabi@4.53.2':
optional: true
'@rollup/rollup-android-arm64@4.53.1':
'@rollup/rollup-android-arm64@4.53.2':
optional: true
'@rollup/rollup-darwin-arm64@4.53.1':
'@rollup/rollup-darwin-arm64@4.53.2':
optional: true
'@rollup/rollup-darwin-x64@4.53.1':
'@rollup/rollup-darwin-x64@4.53.2':
optional: true
'@rollup/rollup-freebsd-arm64@4.53.1':
'@rollup/rollup-freebsd-arm64@4.53.2':
optional: true
'@rollup/rollup-freebsd-x64@4.53.1':
'@rollup/rollup-freebsd-x64@4.53.2':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.53.1':
'@rollup/rollup-linux-arm-gnueabihf@4.53.2':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.53.1':
'@rollup/rollup-linux-arm-musleabihf@4.53.2':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.53.1':
'@rollup/rollup-linux-arm64-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-arm64-musl@4.53.1':
'@rollup/rollup-linux-arm64-musl@4.53.2':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.53.1':
'@rollup/rollup-linux-loong64-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.53.1':
'@rollup/rollup-linux-ppc64-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.53.1':
'@rollup/rollup-linux-riscv64-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.53.1':
'@rollup/rollup-linux-riscv64-musl@4.53.2':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.53.1':
'@rollup/rollup-linux-s390x-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-x64-gnu@4.53.1':
'@rollup/rollup-linux-x64-gnu@4.53.2':
optional: true
'@rollup/rollup-linux-x64-musl@4.53.1':
'@rollup/rollup-linux-x64-musl@4.53.2':
optional: true
'@rollup/rollup-openharmony-arm64@4.53.1':
'@rollup/rollup-openharmony-arm64@4.53.2':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.53.1':
'@rollup/rollup-win32-arm64-msvc@4.53.2':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.53.1':
'@rollup/rollup-win32-ia32-msvc@4.53.2':
optional: true
'@rollup/rollup-win32-x64-gnu@4.53.1':
'@rollup/rollup-win32-x64-gnu@4.53.2':
optional: true
'@rollup/rollup-win32-x64-msvc@4.53.1':
'@rollup/rollup-win32-x64-msvc@4.53.2':
optional: true
'@sindresorhus/is@0.7.0': {}
@@ -3806,14 +3806,14 @@ snapshots:
dependencies:
'@types/node': 24.10.0
'@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.46.3
'@typescript-eslint/type-utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.46.3
'@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.46.4
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -3823,41 +3823,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.46.3
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.46.3
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.46.4
debug: 4.4.3
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.46.3(typescript@5.9.3)':
'@typescript-eslint/project-service@8.46.4(typescript@5.9.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3)
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
'@typescript-eslint/types': 8.46.4
debug: 4.4.3
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.46.3':
'@typescript-eslint/scope-manager@8.46.4':
dependencies:
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/visitor-keys': 8.46.3
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/visitor-keys': 8.46.4
'@typescript-eslint/tsconfig-utils@8.46.3(typescript@5.9.3)':
'@typescript-eslint/tsconfig-utils@8.46.4(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
'@typescript-eslint/type-utils@8.46.3(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3865,14 +3865,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.46.3': {}
'@typescript-eslint/types@8.46.4': {}
'@typescript-eslint/typescript-estree@8.46.3(typescript@5.9.3)':
'@typescript-eslint/typescript-estree@8.46.4(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.46.3(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3)
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/visitor-keys': 8.46.3
'@typescript-eslint/project-service': 8.46.4(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/visitor-keys': 8.46.4
debug: 4.4.3
fast-glob: 3.3.3
is-glob: 4.0.3
@@ -3883,20 +3883,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
'@typescript-eslint/scope-manager': 8.46.3
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.46.3':
'@typescript-eslint/visitor-keys@8.46.4':
dependencies:
'@typescript-eslint/types': 8.46.3
'@typescript-eslint/types': 8.46.4
eslint-visitor-keys: 4.2.1
acorn-jsx@5.3.2(acorn@8.15.0):
@@ -5621,41 +5621,41 @@ snapshots:
dependencies:
glob: 7.2.3
rollup-plugin-visualizer@6.0.5(rollup@4.53.1):
rollup-plugin-visualizer@6.0.5(rollup@4.53.2):
dependencies:
open: 8.4.2
picomatch: 4.0.3
source-map: 0.7.6
yargs: 17.7.2
optionalDependencies:
rollup: 4.53.1
rollup: 4.53.2
rollup@4.53.1:
rollup@4.53.2:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.53.1
'@rollup/rollup-android-arm64': 4.53.1
'@rollup/rollup-darwin-arm64': 4.53.1
'@rollup/rollup-darwin-x64': 4.53.1
'@rollup/rollup-freebsd-arm64': 4.53.1
'@rollup/rollup-freebsd-x64': 4.53.1
'@rollup/rollup-linux-arm-gnueabihf': 4.53.1
'@rollup/rollup-linux-arm-musleabihf': 4.53.1
'@rollup/rollup-linux-arm64-gnu': 4.53.1
'@rollup/rollup-linux-arm64-musl': 4.53.1
'@rollup/rollup-linux-loong64-gnu': 4.53.1
'@rollup/rollup-linux-ppc64-gnu': 4.53.1
'@rollup/rollup-linux-riscv64-gnu': 4.53.1
'@rollup/rollup-linux-riscv64-musl': 4.53.1
'@rollup/rollup-linux-s390x-gnu': 4.53.1
'@rollup/rollup-linux-x64-gnu': 4.53.1
'@rollup/rollup-linux-x64-musl': 4.53.1
'@rollup/rollup-openharmony-arm64': 4.53.1
'@rollup/rollup-win32-arm64-msvc': 4.53.1
'@rollup/rollup-win32-ia32-msvc': 4.53.1
'@rollup/rollup-win32-x64-gnu': 4.53.1
'@rollup/rollup-win32-x64-msvc': 4.53.1
'@rollup/rollup-android-arm-eabi': 4.53.2
'@rollup/rollup-android-arm64': 4.53.2
'@rollup/rollup-darwin-arm64': 4.53.2
'@rollup/rollup-darwin-x64': 4.53.2
'@rollup/rollup-freebsd-arm64': 4.53.2
'@rollup/rollup-freebsd-x64': 4.53.2
'@rollup/rollup-linux-arm-gnueabihf': 4.53.2
'@rollup/rollup-linux-arm-musleabihf': 4.53.2
'@rollup/rollup-linux-arm64-gnu': 4.53.2
'@rollup/rollup-linux-arm64-musl': 4.53.2
'@rollup/rollup-linux-loong64-gnu': 4.53.2
'@rollup/rollup-linux-ppc64-gnu': 4.53.2
'@rollup/rollup-linux-riscv64-gnu': 4.53.2
'@rollup/rollup-linux-riscv64-musl': 4.53.2
'@rollup/rollup-linux-s390x-gnu': 4.53.2
'@rollup/rollup-linux-x64-gnu': 4.53.2
'@rollup/rollup-linux-x64-musl': 4.53.2
'@rollup/rollup-openharmony-arm64': 4.53.2
'@rollup/rollup-win32-arm64-msvc': 4.53.2
'@rollup/rollup-win32-ia32-msvc': 4.53.2
'@rollup/rollup-win32-x64-gnu': 4.53.2
'@rollup/rollup-win32-x64-msvc': 4.53.2
fsevents: 2.3.3
run-parallel@1.2.0:
@@ -5919,12 +5919,12 @@ snapshots:
dependencies:
typescript: 5.9.3
typescript-eslint@8.46.3(eslint@9.39.1)(typescript@5.9.3):
typescript-eslint@8.46.4(eslint@9.39.1)(typescript@5.9.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/eslint-plugin': 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
@@ -6026,7 +6026,7 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.53.1
rollup: 4.53.2
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.0

View File

@@ -13,6 +13,7 @@ const Customizations = lazy(() => import('app/main/Customizations'));
const Scheduler = lazy(() => import('app/main/Scheduler'));
const CustomEntities = lazy(() => import('app/main/CustomEntities'));
const Modules = lazy(() => import('app/main/Modules'));
const UserProfile = lazy(() => import('app/main/UserProfile'));
const Status = lazy(() => import('app/status/Status'));
const HardwareStatus = lazy(() => import('app/status/HardwareStatus'));
@@ -43,6 +44,7 @@ const AuthenticatedRouting = memo(() => {
<Route path="/devices/*" element={<Devices />} />
<Route path="/sensors/*" element={<Sensors />} />
<Route path="/help/*" element={<Help />} />
<Route path="/user/*" element={<UserProfile />} />
<Route path="/status/*" element={<Status />} />
<Route path="/status/hardwarestatus/*" element={<HardwareStatus />} />

View File

@@ -364,6 +364,7 @@ const Customizations = () => {
toast.error((error as Error).message);
} finally {
setConfirmReset(false);
setRestarting(true);
}
}, [sendResetCustomizations, LL]);
@@ -519,6 +520,14 @@ const Customizations = () => {
{LL.RENAME()}
</Button>
))}
<Button
startIcon={<SettingsBackupRestoreIcon />}
variant="outlined"
color="error"
onClick={() => setConfirmReset(true)}
>
{LL.REMOVE_ALL()}
</Button>
</Box>
</>
);
@@ -687,7 +696,7 @@ const Customizations = () => {
open={confirmReset}
onClose={() => setConfirmReset(false)}
>
<DialogTitle>{LL.RESET(1)}</DialogTitle>
<DialogTitle>{LL.REMOVE_ALL()}</DialogTitle>
<DialogContent dividers>{LL.CUSTOMIZATIONS_RESET()}</DialogContent>
<DialogActions>
<Button
@@ -704,7 +713,7 @@ const Customizations = () => {
onClick={resetCustomization}
color="error"
>
{LL.RESET(0)}
{LL.REMOVE_ALL()}
</Button>
</DialogActions>
</Dialog>
@@ -753,18 +762,6 @@ const Customizations = () => {
</ButtonRow>
)}
</Box>
{!rename && (
<ButtonRow mt={1}>
<Button
startIcon={<SettingsBackupRestoreIcon />}
variant="outlined"
color="error"
onClick={() => setConfirmReset(true)}
>
{LL.RESET(0)}
</Button>
</ButtonRow>
)}
</Box>
)}
{renderResetDialog()}

View File

@@ -283,8 +283,6 @@ const Dashboard = memo(() => {
</MessageBox>
)}
{data.nodes.length > 0 && (
<>
<Box
display="flex"
justifyContent="flex-end"
@@ -309,19 +307,9 @@ const Dashboard = memo(() => {
</ToggleButton>
</ButtonTooltip>
</ToggleButtonGroup>
<Tooltip title={LL.DASHBOARD_1()}>
<HelpOutlineIcon
sx={{
ml: 1,
mt: 1,
fontSize: 20,
verticalAlign: 'middle'
}}
color="primary"
/>
</Tooltip>
</Box>
{data.nodes.length > 0 ? (
<Box mt={1} justifyContent="center" flexDirection="column">
<IconContext.Provider
value={{
@@ -358,10 +346,7 @@ const Dashboard = memo(() => {
<Cell>
{me.admin &&
di.dv?.c &&
!hasMask(
di.dv.id,
DeviceEntityMask.DV_READONLY
) && (
!hasMask(di.dv.id, DeviceEntityMask.DV_READONLY) && (
<IconButton
size="small"
aria-label={
@@ -391,7 +376,28 @@ const Dashboard = memo(() => {
</Table>
</IconContext.Provider>
</Box>
</>
) : (
<Box
display="flex"
// justifyContent="flex-end"
// flexWrap="nowrap"
// whiteSpace="nowrap"
>
<Typography mt={1} color="warning.main" variant="body1">
no data
</Typography>
<Tooltip title={LL.DASHBOARD_1()}>
<HelpOutlineIcon
sx={{
ml: 1,
mt: 1,
fontSize: 20,
verticalAlign: 'middle'
}}
color="primary"
/>
</Tooltip>
</Box>
)}
</>
);

View File

@@ -0,0 +1,55 @@
import { memo, useCallback, useContext } from 'react';
import PersonIcon from '@mui/icons-material/Person';
import { Avatar, Box, Button, List, ListItem, ListItemText } from '@mui/material';
import { AuthenticatedContext } from '@/contexts/authentication';
import { SectionContent, useLayoutTitle } from 'components';
import { LanguageSelector } from 'components/inputs';
import { useI18nContext } from 'i18n/i18n-react';
const UserProfileComponent = () => {
const { LL } = useI18nContext();
const { me, signOut } = useContext(AuthenticatedContext);
useLayoutTitle(LL.USER(1));
const handleSignOut = useCallback(() => {
signOut(true);
}, [signOut]);
return (
<SectionContent>
<Box padding={2} justifyContent="center" flexDirection="column">
<Box display="flex" alignItems="center" justifyContent="space-between">
<List sx={{ flexGrow: 1 }}>
<ListItem disablePadding>
<Avatar sx={{ bgcolor: '#9e9e9e', color: 'white' }}>
<PersonIcon />
</Avatar>
<ListItemText
sx={{ pl: 2, color: '#2196f3' }}
primary={me.username}
secondary={'(' + (me.admin ? LL.ADMINISTRATOR() : LL.GUEST()) + ')'}
/>
</ListItem>
</List>
<LanguageSelector />
</Box>
<Button
sx={{ mt: 2 }}
variant="outlined"
fullWidth
color="primary"
onClick={handleSignOut}
>
{LL.SIGN_OUT()}
</Button>
</Box>
</SectionContent>
);
};
const UserProfile = memo(UserProfileComponent);
export default UserProfile;

View File

@@ -370,13 +370,17 @@ const MqttSettings = () => {
>
<MenuItem value={0}>{LL.MQTT_ENTITY_FORMAT_0()}</MenuItem>
<MenuItem value={3}>
{LL.MQTT_ENTITY_FORMAT_1()}&nbsp;(v3.6)
{LL.MQTT_ENTITY_FORMAT_1()}&nbsp;(v3.5)
</MenuItem>
<MenuItem value={4}>
{LL.MQTT_ENTITY_FORMAT_2()}&nbsp;(v3.6)
{LL.MQTT_ENTITY_FORMAT_2()}&nbsp;(v3.5)
</MenuItem>
<MenuItem value={1}>
{LL.MQTT_ENTITY_FORMAT_1()}&nbsp;(latest)
</MenuItem>
<MenuItem value={2}>
{LL.MQTT_ENTITY_FORMAT_2()}&nbsp;(latest)
</MenuItem>
<MenuItem value={1}>{LL.MQTT_ENTITY_FORMAT_1()}</MenuItem>
<MenuItem value={2}>{LL.MQTT_ENTITY_FORMAT_2()}</MenuItem>
</TextField>
</Grid>
</Grid>

View File

@@ -1,4 +1,4 @@
import { memo, useCallback, useContext, useMemo, useState } from 'react';
import { memo, useCallback, useContext, useState } from 'react';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import AssessmentIcon from '@mui/icons-material/Assessment';
@@ -7,51 +7,21 @@ import ConstructionIcon from '@mui/icons-material/Construction';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import LiveHelpIcon from '@mui/icons-material/LiveHelp';
import MoreTimeIcon from '@mui/icons-material/MoreTime';
import PersonIcon from '@mui/icons-material/Person';
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
import SensorsIcon from '@mui/icons-material/Sensors';
import SettingsIcon from '@mui/icons-material/Settings';
import StarIcon from '@mui/icons-material/Star';
import {
Avatar,
Box,
Button,
Divider,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Popover
} from '@mui/material';
import { Box, Divider, List, ListItemButton, ListItemText } from '@mui/material';
import { LanguageSelector } from 'components/inputs';
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
const LayoutMenuComponent = () => {
const { me, signOut } = useContext(AuthenticatedContext);
const { me } = useContext(AuthenticatedContext);
const { LL } = useI18nContext();
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const [menuOpen, setMenuOpen] = useState(true);
const open = useMemo(() => Boolean(anchorEl), [anchorEl]);
const id = useMemo(() => (anchorEl ? 'app-menu-popover' : undefined), [anchorEl]);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
}, []);
const handleClose = useCallback(() => {
setAnchorEl(null);
}, []);
const handleSignOut = useCallback(() => {
signOut(true);
}, [signOut]);
const handleMenuToggle = useCallback(() => {
setMenuOpen((prev) => !prev);
}, []);
@@ -139,64 +109,9 @@ const LayoutMenuComponent = () => {
to="/settings"
/>
<LayoutMenuItem icon={LiveHelpIcon} label={LL.HELP()} to={`/help`} />
</List>
<Divider />
<List>
<ListItem disablePadding>
<ListItemButton component="button" onClick={handleClick}>
<ListItemIcon sx={{ color: '#9e9e9e' }}>
<AccountCircleIcon />
</ListItemIcon>
<ListItemText sx={{ color: '#2196f3' }}>{me.username}</ListItemText>
</ListItemButton>
</ListItem>
<LayoutMenuItem icon={AccountCircleIcon} label={me.username} to={`/user`} />
</List>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center'
}}
>
<Box
padding={2}
justifyContent="center"
flexDirection="column"
sx={{
borderRadius: 3,
border: '3px solid grey'
}}
>
<Button
variant="outlined"
fullWidth
color="primary"
onClick={handleSignOut}
>
{LL.SIGN_OUT()}
</Button>
<List>
<ListItem disablePadding>
<Avatar sx={{ bgcolor: '#9e9e9e', color: 'white' }}>
<PersonIcon />
</Avatar>
<ListItemText
sx={{ pl: 2, color: '#2196f3' }}
primary={me.username}
secondary={'(' + (me.admin ? LL.ADMINISTRATOR() : LL.GUEST()) + ')'}
/>
</ListItem>
</List>
<LanguageSelector />
</Box>
</Popover>
</>
);
};

View File

@@ -27,13 +27,11 @@ const LayoutMenuItemComponent = ({
const buttonStyles: SxProps<Theme> = useMemo(
() => ({
transition: 'all 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)',
transform: selected ? 'scale(1.02)' : 'scale(1)',
backgroundColor: selected ? 'rgba(144, 202, 249, 0.1)' : 'transparent',
borderRadius: '8px',
margin: '2px 8px',
'&:hover': {
backgroundColor: 'rgba(68, 82, 211, 0.39)',
transform: selected ? 'scale(1.02)' : 'scale(1.01)'
backgroundColor: 'rgba(68, 82, 211, 0.39)'
},
'&::before': {
content: '""',

View File

@@ -40,7 +40,7 @@ const cz: Translation = {
RUN_COMMAND: 'Zavolat příkaz',
CHANGE_VALUE: 'Změnit hodnotu',
CANCEL: 'Zrušit',
RESET: 'Resetovat',
REMOVE_ALL: 'Odebrat vše',
APPLY_CHANGES: 'Použít změny ({0})',
UPDATE: 'Aktualizovat',
EXECUTE: 'Provést',
@@ -153,7 +153,7 @@ const cz: Translation = {
SET_ALL: 'nastavit vše',
OPTIONS: 'Možnosti',
NAME: 'Název',
CUSTOMIZATIONS_RESET: 'Opravdu chcete odstranit všechna přizpůsobení včetně vlastních nastavení teplotních a analogových senzorů?',
CUSTOMIZATIONS_RESET: 'Opravdu chcete odstranit všechna přizpůsobení?',
SUPPORT_INFORMATION: 'Podpora',
HELP_INFORMATION_1: 'Navštivte online wiki pro pokyny, jak konfigurovat EMS-ESP',
HELP_INFORMATION_2: 'Pro živý chat s komunitou se připojte k našemu serveru Discord',
@@ -354,7 +354,8 @@ const cz: Translation = {
RELEASE_TYPE: 'Typ sestavení',
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru'
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
NO_DATA: 'Žádná data'
};
export default cz;

View File

@@ -40,7 +40,7 @@ const de: Translation = {
RUN_COMMAND: 'Befehl ausführen',
CHANGE_VALUE: 'Wert ändern',
CANCEL: 'Abbrechen',
RESET: 'Zurücksetzen',
REMOVE_ALL: 'Entfernen alles',
APPLY_CHANGES: 'Änderungen anwenden ({0})',
UPDATE: 'Aktualisieren',
EXECUTE: 'Ausführen',
@@ -153,7 +153,7 @@ const de: Translation = {
SET_ALL: 'Setzen Sie alle',
OPTIONS: 'Optionen',
NAME: 'Name',
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?',
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen?',
SUPPORT_INFORMATION: 'Unterstützende Informationen',
HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki',
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
@@ -354,7 +354,8 @@ const de: Translation = {
RELEASE_TYPE: 'Release Typ',
INTERNET_CONNECTION_REQUIRED: 'Für die automatische Versionsprüfung und Aktualisierung ist eine Internetverbindung erforderlich',
SWITCH_RELEASE_TYPE: 'Zum {0}-Release wechseln',
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation'
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
NO_DATA: 'Keine Daten'
};
export default de;

View File

@@ -40,7 +40,7 @@ const en: Translation = {
RUN_COMMAND: 'Call Command',
CHANGE_VALUE: 'Change Value',
CANCEL: 'Cancel',
RESET: 'Reset',
REMOVE_ALL: 'Remove All',
APPLY_CHANGES: 'Apply Changes ({0})',
UPDATE: 'Update',
EXECUTE: 'Execute',
@@ -153,7 +153,7 @@ const en: Translation = {
SET_ALL: 'set all',
OPTIONS: 'Options',
NAME: 'Name',
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?',
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all the customizations?',
SUPPORT_INFORMATION: 'Support Information',
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
HELP_INFORMATION_2: 'For live community chat join our Discord server',
@@ -354,7 +354,8 @@ const en: Translation = {
RELEASE_TYPE: 'Release Type',
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
SWITCH_RELEASE_TYPE: 'Switch to {0} release',
FIRMWARE_VERSION_INFO: 'Firmware Version Information'
FIRMWARE_VERSION_INFO: 'Firmware Version Information',
NO_DATA: 'No data'
};
export default en;

View File

@@ -40,7 +40,7 @@ const fr: Translation = {
RUN_COMMAND: 'Lancer une commande',
CHANGE_VALUE: 'Changer la valeur',
CANCEL: 'Annuler',
RESET: 'Réinitialiser',
REMOVE_ALL: 'Supprimer tout',
APPLY_CHANGES: 'Appliquer les changements ({0})',
UPDATE: 'Update',
EXECUTE: 'Execute',
@@ -153,7 +153,7 @@ const fr: Translation = {
SET_ALL: 'tout régler',
OPTIONS: 'Options',
NAME: 'Nom',
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations, y compris les paramètres personnalisés des capteurs de température et analogiques ?',
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations?',
SUPPORT_INFORMATION: 'Information de support',
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP',
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
@@ -354,7 +354,8 @@ const fr: Translation = {
RELEASE_TYPE: 'Type de version',
INTERNET_CONNECTION_REQUIRED: 'Connexion Internet requise pour la vérification automatique des versions et la mise à niveau',
SWITCH_RELEASE_TYPE: 'Passer à la version {0}',
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware'
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
NO_DATA: 'Aucune donnée'
};
export default fr;

View File

@@ -40,7 +40,7 @@ const it: Translation = {
RUN_COMMAND: 'Esegui',
CHANGE_VALUE: 'Cambia Valore',
CANCEL: 'Annulla',
RESET: 'Reset',
REMOVE_ALL: 'Rimuovi tutto',
APPLY_CHANGES: 'Applica Cambiamenti ({0})',
UPDATE: 'Update',
EXECUTE: 'Execute',
@@ -153,7 +153,7 @@ const it: Translation = {
SET_ALL: 'imposta tutto',
OPTIONS: 'Opzioni',
NAME: 'Nome',
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni incluse le impostazioni personalizzate dei sensori di temperatura e analogici?',
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni?',
SUPPORT_INFORMATION: 'Informazioni di Supporto',
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
@@ -354,7 +354,8 @@ const it: Translation = {
RELEASE_TYPE: 'Tipo di rilascio',
INTERNET_CONNECTION_REQUIRED: 'Connessione internet richiesta per il controllo automatico delle versioni e l\'aggiornamento',
SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio',
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware'
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
NO_DATA: 'Nessun dato'
};
export default it;

View File

@@ -40,7 +40,7 @@ const nl: Translation = {
RUN_COMMAND: 'Call commando',
CHANGE_VALUE: 'Wijzig waarde',
CANCEL: 'Annuleren',
RESET: 'Reset',
REMOVE_ALL: 'Verwijderen alles',
APPLY_CHANGES: 'Aanpassen ({0})',
UPDATE: 'Update',
EXECUTE: 'Uitvoeren',
@@ -153,7 +153,7 @@ const nl: Translation = {
SET_ALL: 'Alles aanzetten',
OPTIONS: 'Opties',
NAME: 'Naam',
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?',
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen?',
SUPPORT_INFORMATION: 'Support Informatie',
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
@@ -354,7 +354,8 @@ const nl: Translation = {
RELEASE_TYPE: 'Release Typ',
INTERNET_CONNECTION_REQUIRED: 'Internetverbinding vereist voor automatische versiecontrole en -upgrade',
SWITCH_RELEASE_TYPE: 'Switch naar {0} release',
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie'
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
NO_DATA: 'Geen data'
};
export default nl;

View File

@@ -40,7 +40,7 @@ const no: Translation = {
RUN_COMMAND: 'Kjør kommando',
CHANGE_VALUE: 'Endre Verdi',
CANCEL: 'Avbryt',
RESET: 'Nullstill',
REMOVE_ALL: 'Fjern alles',
APPLY_CHANGES: 'Utfør endringer({0})',
UPDATE: 'Oppdater',
EXECUTE: 'Utfør',
@@ -153,7 +153,7 @@ const no: Translation = {
SET_ALL: 'sett alle',
OPTIONS: 'Alternativ',
NAME: 'Navn',
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger inkludert innstillinger for Temperatur og Analoge sensorer?',
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger?',
SUPPORT_INFORMATION: 'Supportinformasjon',
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
@@ -354,7 +354,8 @@ const no: Translation = {
RELEASE_TYPE: 'Utgivelses type',
INTERNET_CONNECTION_REQUIRED: 'Internettilkobling kreves for automatisk versjonskontroll og oppgradering',
SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse',
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon'
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
NO_DATA: 'Ingen data'
};
export default no;

View File

@@ -40,7 +40,7 @@ const pl: BaseTranslation = {
RUN_COMMAND: 'Wykonaj komendę',
CHANGE_VALUE: 'Zmiana wartości',
CANCEL: 'Anuluj',
RESET: 'Reset{{uj|owanie|}}',
REMOVE_ALL: 'Usuń wszystko',
APPLY_CHANGES: 'Zapisz zmiany ({0})',
UPDATE: 'Zmień',
EXECUTE: 'Wykonaj',
@@ -153,7 +153,7 @@ const pl: BaseTranslation = {
SET_ALL: 'Ustaw wszystko jako',
OPTIONS: 'Opcje',
NAME: '{{Nazwa|nazwa|}}',
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje?',
SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
HELP_INFORMATION_1: 'Skorzystaj z wiki w internecie aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP',
HELP_INFORMATION_2: 'Dołącz do naszego serwera Discord by komunikować się na żywo ze społecznością',
@@ -354,7 +354,8 @@ const pl: BaseTranslation = {
RELEASE_TYPE: 'Typ wydania',
INTERNET_CONNECTION_REQUIRED: 'Połączenie internetowe jest wymagane do automatycznej kontroli wersji i aktualizacji',
SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie',
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware'
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
NO_DATA: 'Brak danych'
};
export default pl;

View File

@@ -40,7 +40,7 @@ const sk: Translation = {
RUN_COMMAND: 'Volať príkaz',
CHANGE_VALUE: 'Zmena hodnoty',
CANCEL: 'Zrušiť',
RESET: 'Reset',
REMOVE_ALL: 'Odstrániť všetko',
APPLY_CHANGES: 'Aplikovať zmeny ({0})',
UPDATE: 'Aktualizovať',
EXECUTE: 'Spustiť',
@@ -153,7 +153,7 @@ const sk: Translation = {
SET_ALL: 'nastaviť všetko',
OPTIONS: 'Možnosti',
NAME: 'Názov',
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia?',
SUPPORT_INFORMATION: 'Informácie pre podporu',
HELP_INFORMATION_1: 'Navštívte online wiki, kde nájdete pokyny na konfiguráciu EMS-ESP',
HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server',
@@ -354,7 +354,8 @@ const sk: Translation = {
RELEASE_TYPE: 'Typ vydania',
INTERNET_CONNECTION_REQUIRED: 'Internetové pripojenie je potrebné pre automatickú kontrolu a aktualizáciu',
SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu',
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware'
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
NO_DATA: 'Žiadne dáta'
};
export default sk;

View File

@@ -40,7 +40,7 @@ const sv: Translation = {
RUN_COMMAND: 'Kör kommando',
CHANGE_VALUE: 'Ändra värde',
CANCEL: 'Avbryt',
RESET: 'Nollställ',
REMOVE_ALL: 'Ta bort allt',
APPLY_CHANGES: 'Utför ändringar ({0})',
UPDATE: 'Uppdatera',
EXECUTE: 'Utför',
@@ -153,7 +153,7 @@ const sv: Translation = {
SET_ALL: 'ställ in alla',
OPTIONS: 'Alternativ',
NAME: 'Namn',
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar, inklusive inställningar för Temperatursensorer och Analoga sensorer?',
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar?',
SUPPORT_INFORMATION: 'Supportinformation',
HELP_INFORMATION_1: 'Besök Wikin för instruktioner om hur du kan konfigurera EMS-ESP',
HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
@@ -354,7 +354,8 @@ const sv: Translation = {
RELEASE_TYPE: 'Utgivelsestyp',
INTERNET_CONNECTION_REQUIRED: 'Internetanslutning krävs för automatisk version kontroll och uppdatering',
SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva',
FIRMWARE_VERSION_INFO: 'Information om firmwareversion'
FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
NO_DATA: 'Ingen data'
};
export default sv;

View File

@@ -40,8 +40,8 @@ const tr: Translation = {
RUN_COMMAND: 'Çalıştırma Komutu',
CHANGE_VALUE: 'Değeri Değiştir',
CANCEL: 'İptal',
RESET: 'Reset',
APPLY_CHANGES: 'Apply Changes ({0})',
REMOVE_ALL: 'Tümünü Kaldır',
APPLY_CHANGES: 'Değişiklikleri Uygula ({0})',
UPDATE: 'Update',
EXECUTE: 'Uygulamak',
REMOVE: 'Kaldır',
@@ -153,7 +153,7 @@ const tr: Translation = {
SET_ALL: 'hepsini ayarla',
OPTIONS: 'Seçenekler',
NAME: 'İsim',
CUSTOMIZATIONS_RESET: 'Sıcaklık ve Analog Sensörlerin özelleştirilmiş seçenekleri dahil bütün özelleştirmeleri kaldırmak istediğinizden emin misiniz?',
CUSTOMIZATIONS_RESET: 'Bütün özelleştirmeleri kaldırmak istediğinizden emin misiniz?',
SUPPORT_INFORMATION: 'Destek Bilgileri',
HELP_INFORMATION_1: 'EMS-ESPnin nasıl ayarlanacağı ile ilgili bilgileri edinmek için çevrimiçi WIKI sayfasını ziyaret edin',
HELP_INFORMATION_2: 'Canlı topluluk sohbeti için Discord sunucumuza katılın',
@@ -354,7 +354,8 @@ const tr: Translation = {
RELEASE_TYPE: 'Sürüm Tipi',
INTERNET_CONNECTION_REQUIRED: 'Otomatik sürüm kontrolü ve güncelleme için internet bağlantısı gereklidir',
SWITCH_RELEASE_TYPE: '{0} sürümüne geç',
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi'
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
NO_DATA: 'Hiçbir veri yok'
};
export default tr;

View File

@@ -15,5 +15,5 @@
"itty-router": "^5.0.22",
"prettier": "^3.6.2"
},
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
"packageManager": "pnpm@10.21.0+sha512.da3337267e400fdd3d479a6c68079ac6db01d8ca4f67572083e722775a796788a7a9956613749e000fac20d424b594f7a791a5f4e2e13581c5ef947f26968a40"
}

View File

@@ -4524,7 +4524,7 @@ router
settings = await request.json();
console.log('application settings saved', settings);
return status(200); // no restart needed
// return status(205); // restart needed
// return status(205); // reboot required
})
// Device Data
@@ -4559,9 +4559,8 @@ router
let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } =
{};
let fake = false;
// fake = true; // for testing, shows a subset of data
// let fake = false;
let fake = true; // toggle for testing, shows a subset of data
if (!fake) {
// pick EMS devices from coredata
@@ -4614,8 +4613,7 @@ router
}
// add analog sensor data. no command c
// remove disabled sensors first (t = 0) and create data in one pass
// remove system sensors first
// remove disabled and system sensors first (t = 0) and create data in one pass
const enabledAnalogSensors = emsesp_sensordata.as.filter(
(item) => item.t !== 0 && !item.s
);
@@ -4658,17 +4656,15 @@ router
}
} else {
// for testing only
// add the custom entity data
dashboard_object = {
id: DeviceTypeUniqueID.CUSTOM_UID, // unique ID for custom entities
t: DeviceType.CUSTOM,
nodes: getDashboardEntityData(DeviceTypeUniqueID.CUSTOM_UID)
};
if ((dashboard_object.nodes ?? []).length > 0) {
dashboard_nodes.push(dashboard_object);
}
// dashboard_object = {
// id: DeviceTypeUniqueID.CUSTOM_UID, // unique ID for custom entities
// t: DeviceType.CUSTOM,
// nodes: getDashboardEntityData(DeviceTypeUniqueID.CUSTOM_UID)
// };
// if ((dashboard_object.nodes ?? []).length > 0) {
// dashboard_nodes.push(dashboard_object);
// }
// add the scheduler data
// let scheduler_data = emsesp_schedule.schedule.filter((item) => item.name);
// let scheduler_data2 = scheduler_data.map((item, index) => ({

View File

@@ -164,8 +164,8 @@ class AnalogSensor {
return (!sensors_.empty());
}
size_t count_entities(bool include_disabled = true) const {
if (!include_disabled) {
size_t count_entities(bool exclude_disabled_system = false) const {
if (exclude_disabled_system) {
// count number of items in sensors_ where type is not set to disabled and not a system sensor
return std::count_if(sensors_.begin(), sensors_.end(), [](const Sensor & sensor) {
return sensor.type() != AnalogSensor::AnalogType::NOTUSED && !sensor.is_system();

View File

@@ -1703,9 +1703,6 @@ void EMSESP::start() {
#ifndef EMSESP_STANDALONE
File root = LittleFS.open(EMSESP_SETTINGS_FILE);
bool factory_settings = !root;
if (!root) {
LOG_WARNING("No settings found on filesystem. Using factory settings.");
}
root.close();
#else
bool factory_settings = false;
@@ -1717,6 +1714,12 @@ void EMSESP::start() {
// loads core system services settings (network, mqtt, ap, ntp etc)
esp32React.begin();
#ifndef EMSESP_STANDALONE
if (factory_settings) {
LOG_WARNING("No settings found on filesystem. Using factory settings.");
}
#endif
#ifndef EMSESP_STANDALONE
LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION);
LOG_DEBUG("Boot partition %s, Active partition %s", esp_ota_get_boot_partition()->label, esp_ota_get_running_partition()->label);

View File

@@ -160,8 +160,10 @@ void TemperatureSensor::loop() {
}
// add new sensor. this will create the id string, empty name and offset
if (!found && (sensors_.size() < (MAX_SENSORS - 1))) {
// LOG_NOTICE("Adding new sensor for %s", Sensor(addr).id().c_str());
sensors_.emplace_back(addr);
sensors_.back().read = true;
sensors_.back().set_is_system(false);
changed_ = true;
// look in the customization service for an optional alias or offset for that particular sensor
sensors_.back().apply_customization();
@@ -189,7 +191,6 @@ void TemperatureSensor::loop() {
bus_.depower();
}
// check for missing sensors after some samples
// but don't do this if running in test mode where we simulate sensors
if (++scancnt_ > SCAN_MAX) {
for (auto & sensor : sensors_) {
if (!sensor.read) {
@@ -214,10 +215,11 @@ void TemperatureSensor::loop() {
}
}
s->set_name("gateway_temperature");
s->set_is_system(true); // mark as internal system temperature sensor
if (!EMSESP::nvs_.isKey("intTemp")) {
EMSESP::nvs_.putString("intTemp", s->id().c_str());
}
s->set_is_system(true); // mark as internal system temperature sensor
// LOG_NOTICE("Adding system sensor for gateway temperature %s", s->id().c_str());
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
auto newSensor = SensorCustomization();
newSensor.id = s->id();
@@ -228,7 +230,7 @@ void TemperatureSensor::loop() {
return StateUpdateResult::CHANGED;
});
}
// LOG_DEBUG("Adding %d sensor(s) from first scan", firstscan_);
// LOG_NOTICE("Adding %d sensor(s) from first scan", firstscan_);
} else if ((scancnt_ <= 0) && (firstscan_ != sensors_.size())) { // check 2 times for no change of sensor #
scancnt_ = SCAN_START;
sensors_.clear(); // restart scanning and clear to get correct numbering
@@ -329,6 +331,7 @@ bool TemperatureSensor::update(const std::string & id, const std::string & name,
sensor.set_name(name);
sensor.set_offset(offset);
sensor.set_is_system(is_system);
// store the new name and offset in our configuration
EMSESP::webCustomizationService.update([&id, &name, &offset, &is_system, &sensor](WebCustomization & settings) {
@@ -349,7 +352,7 @@ bool TemperatureSensor::update(const std::string & id, const std::string & name,
newSensor.id = id;
newSensor.name = name;
newSensor.offset = offset;
newSensor.is_system = false; // is user defined, not system
newSensor.is_system = is_system; // is user defined, not system
settings.sensorCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for sensor ID %s", id.c_str());
}
@@ -425,6 +428,7 @@ void TemperatureSensor::get_value_json(JsonObject output, const Sensor & sensor)
output["readable"] = true;
output["writeable"] = false;
output["visible"] = true;
output["is_system"] = sensor.is_system();
}
// publish a single sensor to MQTT
@@ -610,6 +614,7 @@ bool TemperatureSensor::Sensor::apply_customization() {
LOG_DEBUG("Loading customization for temperature sensor %s", sensor.id.c_str());
set_name(sensor.name);
set_offset(sensor.offset);
set_is_system(sensor.is_system);
return true;
}
}

View File

@@ -114,9 +114,9 @@ class TemperatureSensor {
return (!sensors_.empty());
}
size_t count_entities(bool include_system = true) const {
return std::count_if(sensors_.begin(), sensors_.end(), [include_system](const Sensor & sensor) {
return include_system ? sensor.is_system() : !sensor.is_system();
size_t count_entities(bool exclude_disabled_system = false) const {
return std::count_if(sensors_.begin(), sensors_.end(), [exclude_disabled_system](const Sensor & sensor) {
return exclude_disabled_system ? !sensor.is_system() : sensor.is_system();
});
}

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.3-dev.26"
#define EMSESP_APP_VERSION "3.7.3-dev.27"

View File

@@ -160,17 +160,19 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
// deletes the customization file
void WebCustomizationService::reset_customization(AsyncWebServerRequest * request) {
#ifndef EMSESP_STANDALONE
if (LittleFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
AsyncWebServerResponse * response = request->beginResponse(205); // restart needed
EMSESP::webCustomizationService.update([](WebCustomization & settings) {
// remove entityCustomizations
settings.entityCustomizations.clear(); // clear the masked_entities list
return StateUpdateResult::CHANGED;
});
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
emsesp::EMSESP::system_.systemStatus(
emsesp::SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART); // will be handled by the main loop. We use pending for the Web's SystemMonitor
return;
}
// failed
AsyncWebServerResponse * response = request->beginResponse(400); // bad request
request->send(response);
#endif
}

View File

@@ -423,7 +423,7 @@ void WebDataService::dashboard_data(AsyncWebServerRequest * request) {
}
// add analog sensors, count excludes disabled entries
if (EMSESP::analog_enabled() && EMSESP::analogsensor_.count_entities(false)) {
if (EMSESP::analog_enabled() && EMSESP::analogsensor_.count_entities(true)) {
JsonObject obj = nodes.add<JsonObject>();
obj["id"] = EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID; // it's unique id
obj["t"] = EMSdevice::DeviceType::ANALOGSENSOR; // device type number

View File

@@ -1,13 +1,14 @@
// ---------- START - CUT HERE ----------
void test_1() {
auto expected_response = "[{\"reset\":\"\",\"heatingoff\":\"off\",\"heatingactive\":\"off\",\"tapwateractive\":\"on\",\"selflowtemp\":0,\"curflowtemp\":60."
"2,\"rettemp\":48.1,\"syspress\":1.4,\"burngas\":\"on\",\"burngas2\":\"off\",\"flamecurr\":37.4,\"fanwork\":\"on\",\"ignwork\":"
"\"off\",\"oilpreheat\":\"off\",\"heatingpump\":\"on\",\"selburnpow\":115,\"curburnpow\":61,\"ubauptime\":3940268,\"servicecode\":"
"\"=H\",\"servicecodenumber\":201,\"nompower\":0,\"nrgtotal\":0.0,\"nrgheat\":0.0,\"dhw\":{\"seltemp\":52,\"comfort\":\"hot\","
"\"flowtempoffset\":40,\"chargeoptimization\":\"off\",\"circpump\":\"off\",\"chargetype\":\"3-way "
"valve\",\"hyston\":-5,\"disinfectiontemp\":70,\"circmode\":\"off\",\"circ\":\"off\",\"storagetemp1\":53.8,\"activated\":\"on\","
"\"3wayvalve\":\"on\",\"chargepump\":\"off\",\"nrg\":0.0}}]";
auto expected_response =
"[{\"reset\":\"\",\"chimneysweeper\":\"\",\"heatingoff\":\"off\",\"heatingactive\":\"off\",\"tapwateractive\":\"on\",\"selflowtemp\":0,\"curflowtemp\":"
"60.2,\"rettemp\":48.1,\"syspress\":1.4,\"burngas\":\"on\",\"burngas2\":\"off\",\"flamecurr\":37.4,\"fanwork\":\"on\",\"ignwork\":\"off\","
"\"oilpreheat\":\"off\",\"heatingpump\":\"on\",\"selburnpow\":115,\"curburnpow\":61,\"ubauptime\":3940268,\"servicecode\":\"=H\",\"servicecodenumber\":"
"201,\"nompower\":0,\"nrgtotal\":0.0,\"nrgheat\":0.0,\"dhw\":{\"seltemp\":52,\"comfort\":\"hot\",\"flowtempoffset\":40,\"chargeoptimization\":\"off\","
"\"circpump\":\"off\",\"chargetype\":\"3-way "
"valve\",\"hyston\":-5,\"disinfectiontemp\":70,\"circmode\":\"off\",\"circ\":\"off\",\"storagetemp1\":53.8,\"activated\":\"on\",\"3wayvalve\":\"on\","
"\"chargepump\":\"off\",\"nrg\":0.0}}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler"));
}
@@ -16,9 +17,10 @@ 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\",\"burnminpower\":\"burner min power\",\"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\",\"burnminpower\":\"burner min power\",\"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].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 "
@@ -36,30 +38,31 @@ void test_2() {
}
void test_3() {
auto expected_response = "[{\"reset\":\"\",\"heatingoff\":\"off\",\"heatingactive\":\"off\",\"tapwateractive\":\"on\",\"selflowtemp\":0,\"curflowtemp\":60."
"2,\"rettemp\":48.1,\"syspress\":1.4,\"burngas\":\"on\",\"burngas2\":\"off\",\"flamecurr\":37.4,\"fanwork\":\"on\",\"ignwork\":"
"\"off\",\"oilpreheat\":\"off\",\"heatingpump\":\"on\",\"selburnpow\":115,\"curburnpow\":61,\"ubauptime\":3940268,\"servicecode\":"
"\"=H\",\"servicecodenumber\":201,\"nompower\":0,\"nrgtotal\":0.0,\"nrgheat\":0.0,\"dhw\":{\"seltemp\":52,\"comfort\":\"hot\","
"\"flowtempoffset\":40,\"chargeoptimization\":\"off\",\"circpump\":\"off\",\"chargetype\":\"3-way "
"valve\",\"hyston\":-5,\"disinfectiontemp\":70,\"circmode\":\"off\",\"circ\":\"off\",\"storagetemp1\":53.8,\"activated\":\"on\","
"\"3wayvalve\":\"on\",\"chargepump\":\"off\",\"nrg\":0.0}}]";
auto expected_response =
"[{\"reset\":\"\",\"chimneysweeper\":\"\",\"heatingoff\":\"off\",\"heatingactive\":\"off\",\"tapwateractive\":\"on\",\"selflowtemp\":0,\"curflowtemp\":"
"60.2,\"rettemp\":48.1,\"syspress\":1.4,\"burngas\":\"on\",\"burngas2\":\"off\",\"flamecurr\":37.4,\"fanwork\":\"on\",\"ignwork\":\"off\","
"\"oilpreheat\":\"off\",\"heatingpump\":\"on\",\"selburnpow\":115,\"curburnpow\":61,\"ubauptime\":3940268,\"servicecode\":\"=H\",\"servicecodenumber\":"
"201,\"nompower\":0,\"nrgtotal\":0.0,\"nrgheat\":0.0,\"dhw\":{\"seltemp\":52,\"comfort\":\"hot\",\"flowtempoffset\":40,\"chargeoptimization\":\"off\","
"\"circpump\":\"off\",\"chargetype\":\"3-way "
"valve\",\"hyston\":-5,\"disinfectiontemp\":70,\"circmode\":\"off\",\"circ\":\"off\",\"storagetemp1\":53.8,\"activated\":\"on\",\"3wayvalve\":\"on\","
"\"chargepump\":\"off\",\"nrg\":0.0}}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/values"));
}
void test_4() {
auto expected_response =
"[{\"reset (reset)\":\"\",\"force heating off (heatingoff)\":\"off\",\"is my heating on? (heatingactive)\":\"off\",\"tapwater active "
"(tapwateractive)\":\"on\",\"selected flow temperature (selflowtemp)\":0,\"current flow temperature (curflowtemp)\":60.2,\"return temperature "
"(rettemp)\":48.1,\"system pressure (syspress)\":1.4,\"gas (burngas)\":\"on\",\"gas stage 2 (burngas2)\":\"off\",\"flame current "
"(flamecurr)\":37.4,\"fan (fanwork)\":\"on\",\"ignition (ignwork)\":\"off\",\"oil preheating (oilpreheat)\":\"off\",\"heating pump "
"(heatingpump)\":\"on\",\"burner selected max power (selburnpow)\":115,\"burner current power (curburnpow)\":61,\"total UBA operating time "
"(ubauptime)\":\"2736 days 7 hours 8 minutes\",\"service code (servicecode)\":\"=H\",\"service code number (servicecodenumber)\":201,\"dhw selected "
"temperature (seltemp)\":52,\"dhw comfort (comfort)\":\"hot\",\"dhw flow temperature offset (flowtempoffset)\":40,\"dhw charge optimization "
"(chargeoptimization)\":\"off\",\"dhw circulation pump available (circpump)\":\"off\",\"dhw charging type (chargetype)\":\"3-way valve\",\"dhw "
"hysteresis on temperature (hyston)\":-5,\"dhw disinfection temperature (disinfectiontemp)\":70,\"dhw circulation pump mode (circmode)\":\"off\",\"dhw "
"circulation active (circ)\":\"off\",\"dhw storage intern temperature (storagetemp1)\":53.8,\"dhw activated (activated)\":\"on\",\"dhw 3-way valve "
"active (3wayvalve)\":\"on\",\"dhw charge pump (chargepump)\":\"off\",\"nominal Power (nompower)\":0,\"total energy (nrgtotal)\":0.0,\"energy heating "
"(nrgheat)\":0.0,\"dhw energy (nrg)\":0.0}]";
"[{\"reset (reset)\":\"\",\"chimney sweeper (chimneysweeper)\":\"\",\"force heating off (heatingoff)\":\"off\",\"is my heating on? "
"(heatingactive)\":\"off\",\"tapwater active (tapwateractive)\":\"on\",\"selected flow temperature (selflowtemp)\":0,\"current flow temperature "
"(curflowtemp)\":60.2,\"return temperature (rettemp)\":48.1,\"system pressure (syspress)\":1.4,\"gas (burngas)\":\"on\",\"gas stage 2 "
"(burngas2)\":\"off\",\"flame current (flamecurr)\":37.4,\"fan (fanwork)\":\"on\",\"ignition (ignwork)\":\"off\",\"oil preheating "
"(oilpreheat)\":\"off\",\"heating pump (heatingpump)\":\"on\",\"burner selected max power (selburnpow)\":115,\"burner current power "
"(curburnpow)\":61,\"total UBA operating time (ubauptime)\":\"2736 days 7 hours 8 minutes\",\"service code (servicecode)\":\"=H\",\"service code "
"number (servicecodenumber)\":201,\"dhw selected temperature (seltemp)\":52,\"dhw comfort (comfort)\":\"hot\",\"dhw flow temperature offset "
"(flowtempoffset)\":40,\"dhw charge optimization (chargeoptimization)\":\"off\",\"dhw circulation pump available (circpump)\":\"off\",\"dhw charging "
"type (chargetype)\":\"3-way valve\",\"dhw hysteresis on temperature (hyston)\":-5,\"dhw disinfection temperature (disinfectiontemp)\":70,\"dhw "
"circulation pump mode (circmode)\":\"off\",\"dhw circulation active (circ)\":\"off\",\"dhw storage intern temperature (storagetemp1)\":53.8,\"dhw "
"activated (activated)\":\"on\",\"dhw 3-way valve active (3wayvalve)\":\"on\",\"dhw charge pump (chargepump)\":\"off\",\"nominal Power "
"(nompower)\":0,\"total energy (nrgtotal)\":0.0,\"energy heating (nrgheat)\":0.0,\"dhw energy (nrg)\":0.0}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/info"));
}
@@ -175,7 +178,7 @@ void test_21() {
"\"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\":38,\"handlersReceived\":\"0x18\","
"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 "
"0x3B\"},{\"type\":\"thermostat\",\"name\":\"FW120\",\"deviceID\":\"0x10\",\"productID\":192,\"brand\":\"\",\"version\":\"01.00\",\"entities\":15,"
@@ -203,7 +206,7 @@ void test_22() {
"\"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\":38,\"handlersReceived\":\"0x18\","
"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 "
"0x3B\"},{\"type\":\"thermostat\",\"name\":\"FW120\",\"deviceID\":\"0x10\",\"productID\":192,\"brand\":\"\",\"version\":\"01.00\",\"entities\":15,"
@@ -258,13 +261,13 @@ void test_30() {
void test_31() {
auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2"));
}
void test_32() {
auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
"\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true,\"is_system\":false}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011"));
}