From 486b365f9b13f77a769415ecf48ac56ce80cfd79 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 31 Mar 2023 16:48:08 +0200 Subject: [PATCH 1/5] update packages --- interface/.typesafe-i18n.json | 2 +- interface/package.json | 28 +-- interface/yarn.lock | 450 ++++++++++++++++++---------------- 3 files changed, 256 insertions(+), 224 deletions(-) diff --git a/interface/.typesafe-i18n.json b/interface/.typesafe-i18n.json index c4dc70594..45ebe9985 100644 --- a/interface/.typesafe-i18n.json +++ b/interface/.typesafe-i18n.json @@ -1,5 +1,5 @@ { "adapter": "react", "baseLocale": "pl", - "$schema": "https://unpkg.com/typesafe-i18n@5.24.2/schema/typesafe-i18n.json" + "$schema": "https://unpkg.com/typesafe-i18n@5.24.3/schema/typesafe-i18n.json" } diff --git a/interface/package.json b/interface/package.json index e0e3b36a1..a0ba1872e 100644 --- a/interface/package.json +++ b/interface/package.json @@ -22,17 +22,17 @@ "dependencies": { "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", - "@msgpack/msgpack": "^2.8.0", + "@msgpack/msgpack": "^3.0.0-beta2", "@mui/icons-material": "^5.11.11", - "@mui/material": "^5.11.14", - "@remix-run/router": "^1.4.0", + "@mui/material": "^5.11.15", + "@remix-run/router": "^1.5.0", "@table-library/react-table-library": "4.1.0", "@types/lodash-es": "^4.17.7", - "@types/node": "^18.15.7", - "@types/react": "^18.0.28", + "@types/node": "^18.15.11", + "@types/react": "^18.0.31", "@types/react-dom": "^18.0.11", "@types/react-router-dom": "^5.3.3", - "@yarnpkg/pnpify": "^4.0.0-rc.40", + "@yarnpkg/pnpify": "^4.0.0-rc.42", "async-validator": "^4.2.5", "axios": "^1.3.4", "history": "^5.3.0", @@ -43,23 +43,23 @@ "react-dom": "latest", "react-dropzone": "^14.2.3", "react-icons": "^4.8.0", - "react-router-dom": "^6.9.0", + "react-router-dom": "^6.10.0", "react-toastify": "^9.1.2", "sockette": "^2.0.6", - "typesafe-i18n": "^5.24.2", - "typescript": "^5.0.2" + "typesafe-i18n": "^5.24.3", + "typescript": "^5.0.3" }, "devDependencies": { "@types/mime-types": "^2", "@types/styled-components": "^5", - "@typescript-eslint/eslint-plugin": "^5.56.0", - "@typescript-eslint/parser": "^5.56.0", + "@typescript-eslint/eslint-plugin": "^5.57.0", + "@typescript-eslint/parser": "^5.57.0", "@vitejs/plugin-react-swc": "^3.2.0", - "eslint": "^8.36.0", + "eslint": "^8.37.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-prettier": "^8.8.0", - "eslint-import-resolver-typescript": "^3.5.3", + "eslint-import-resolver-typescript": "^3.5.4", "eslint-plugin-deprecation": "^1.3.3", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.7.1", @@ -70,7 +70,7 @@ "npm-run-all": "^4.1.5", "prettier": "^2.8.7", "rollup-plugin-visualizer": "^5.9.0", - "terser": "^5.16.6", + "terser": "^5.16.8", "vite": "^4.2.1", "vite-plugin-minify": "^1.5.2", "vite-plugin-svgr": "^2.4.0", diff --git a/interface/yarn.lock b/interface/yarn.lock index 7a6befbd4..f2005d063 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -578,27 +578,27 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.0.1": - version: 2.0.1 - resolution: "@eslint/eslintrc@npm:2.0.1" +"@eslint/eslintrc@npm:^2.0.2": + version: 2.0.2 + resolution: "@eslint/eslintrc@npm:2.0.2" dependencies: ajv: ^6.12.4 debug: ^4.3.2 - espree: ^9.5.0 + espree: ^9.5.1 globals: ^13.19.0 ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: 56b9192a687a450db53a7b883daf9f0f447c43b3510189cf88808a7a2467c2a302a42a50f184cc6d5a9faf3d1df890a2ef0fd0d60b751f32a3e9dfea717c6b48 + checksum: cfcf5e12c7b2c4476482e7f12434e76eae16fcd163ee627309adb10b761e5caa4a4e52ed7be464423320ff3d11eca5b50de5bf8be3e25834222470835dd5c801 languageName: node linkType: hard -"@eslint/js@npm:8.36.0": - version: 8.36.0 - resolution: "@eslint/js@npm:8.36.0" - checksum: b7d6b84b823c8c7784be390741196617565527b1f7c0977fde9455bfb57fd88f81c074a03dd878757d2c33fa29f24291e9ecbc1425710f067917324b55e1bf3a +"@eslint/js@npm:8.37.0": + version: 8.37.0 + resolution: "@eslint/js@npm:8.37.0" + checksum: 7a07fb085c94ce1538949012c292fd3a6cd734f149bc03af6157dfbd8a7477678899ef57b4a27e15b36470a997389ad79a0533d5880c71e67720ae1a7de7c62d languageName: node linkType: hard @@ -696,22 +696,22 @@ __metadata: languageName: node linkType: hard -"@msgpack/msgpack@npm:^2.8.0": - version: 2.8.0 - resolution: "@msgpack/msgpack@npm:2.8.0" - checksum: bead9393f57239007a2fe455df5277cbc03b125f14f310162a652b81471dcf3ab6780eaa24b36e20aa742998910a6840147d08b7267063b8e2de5d40c624360e +"@msgpack/msgpack@npm:^3.0.0-beta2": + version: 3.0.0-beta2 + resolution: "@msgpack/msgpack@npm:3.0.0-beta2" + checksum: d86e5d48146051952d6bea35a6cf733a401cf65ad5614d79689aa48c7076021737ca2c782978dd1b6c0c9c45888b246e379e45ae906179e3a0e8ef4ee6f221c1 languageName: node linkType: hard -"@mui/base@npm:5.0.0-alpha.122": - version: 5.0.0-alpha.122 - resolution: "@mui/base@npm:5.0.0-alpha.122" +"@mui/base@npm:5.0.0-alpha.123": + version: 5.0.0-alpha.123 + resolution: "@mui/base@npm:5.0.0-alpha.123" dependencies: "@babel/runtime": ^7.21.0 "@emotion/is-prop-valid": ^1.2.0 "@mui/types": ^7.2.3 "@mui/utils": ^5.11.13 - "@popperjs/core": ^2.11.6 + "@popperjs/core": ^2.11.7 clsx: ^1.2.1 prop-types: ^15.8.1 react-is: ^18.2.0 @@ -722,14 +722,14 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 6d229f6f736074a41e0cf787cc5ef98eba23a52044d7edf22fcc42f03250275fd1b4bb4a7ab47fc1f1aec06bf777bde5474229cc381e515eefee8876f2d8cd5c + checksum: a17c266d0a922903e43c08cce8f42d1a35716b5d1574393c90ac89290029f6c08ef7261ba7af3609917a32fce1a1c0efdab06320df4d1ab351fd987e429f6dfd languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.11.14": - version: 5.11.14 - resolution: "@mui/core-downloads-tracker@npm:5.11.14" - checksum: 8b1b42e125b15136ee82d2cb48354202b87beb8e20defcf3a8b758b033732444d09446d85a28c23b0dcaa8b5d067bc20bdd654c9adf551d826b142b4b09d7dd7 +"@mui/core-downloads-tracker@npm:^5.11.15": + version: 5.11.15 + resolution: "@mui/core-downloads-tracker@npm:5.11.15" + checksum: 8dc377b415ac1c18ec11a55fe916aeb0317e4c454759e3c3c0d3bdeaef75236486f17cb9ef3ae01eaee5f51e2cc7ada6a7e7ca452a64ddbbb8638c32e2615938 languageName: node linkType: hard @@ -749,14 +749,14 @@ __metadata: languageName: node linkType: hard -"@mui/material@npm:^5.11.14": - version: 5.11.14 - resolution: "@mui/material@npm:5.11.14" +"@mui/material@npm:^5.11.15": + version: 5.11.15 + resolution: "@mui/material@npm:5.11.15" dependencies: "@babel/runtime": ^7.21.0 - "@mui/base": 5.0.0-alpha.122 - "@mui/core-downloads-tracker": ^5.11.14 - "@mui/system": ^5.11.14 + "@mui/base": 5.0.0-alpha.123 + "@mui/core-downloads-tracker": ^5.11.15 + "@mui/system": ^5.11.15 "@mui/types": ^7.2.3 "@mui/utils": ^5.11.13 "@types/react-transition-group": ^4.4.5 @@ -778,7 +778,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 48fdd56ee55da6d551b8b716b8a080afe2276a62e0441efdd58be3b10ab1204d196a8ecc5f35ac23b8e9c7f5d6884ce37966cdcf8846771fe8ccc5ca626a8e1e + checksum: 53726a8aa2ab541c967eda43fe0094486e2f2ac743c39f09a5326aeffdba0be414187f216346c45135751b63a28a9871f4e68f4d6ab89b5b1d86e468f869d328 languageName: node linkType: hard @@ -820,9 +820,9 @@ __metadata: languageName: node linkType: hard -"@mui/system@npm:^5.11.14": - version: 5.11.14 - resolution: "@mui/system@npm:5.11.14" +"@mui/system@npm:^5.11.15": + version: 5.11.15 + resolution: "@mui/system@npm:5.11.15" dependencies: "@babel/runtime": ^7.21.0 "@mui/private-theming": ^5.11.13 @@ -844,7 +844,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: a9df588ee7358438244ba5115f1f3bfe548b4c9077280204b6f6d4b98f20fd93f76bc36bf1430848b64e5c3a495ecb0e5000379932faa3dfb92360a34262f301 + checksum: c8b8ffcf48b204f8e0ff6cc2ef5a35b6a3ef3517c9626dbb2fda073b81992c93750167440737459b82ff1ac2bf6d4e9eb9ce3b39887bdc4dbded5bc8266032ac languageName: node linkType: hard @@ -936,17 +936,17 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.11.6": - version: 2.11.6 - resolution: "@popperjs/core@npm:2.11.6" - checksum: 47fb328cec1924559d759b48235c78574f2d71a8a6c4c03edb6de5d7074078371633b91e39bbf3f901b32aa8af9b9d8f82834856d2f5737a23475036b16817f0 +"@popperjs/core@npm:^2.11.7": + version: 2.11.7 + resolution: "@popperjs/core@npm:2.11.7" + checksum: 5b6553747899683452a1d28898c1b39173a4efd780e74360bfcda8eb42f1c5e819602769c81a10920fc68c881d07fb40429604517d499567eac079cfa6470f19 languageName: node linkType: hard -"@remix-run/router@npm:1.4.0, @remix-run/router@npm:^1.4.0": - version: 1.4.0 - resolution: "@remix-run/router@npm:1.4.0" - checksum: 707dce35a2b8138005cf19e63f6fd3c4da05b4b892e9e9118e8b727c3b95953efe27307ca2df35084044df30fa1fc367cf0bbc98d1ded9020c82e61e6242caaf +"@remix-run/router@npm:1.5.0, @remix-run/router@npm:^1.5.0": + version: 1.5.0 + resolution: "@remix-run/router@npm:1.5.0" + checksum: 9c510c174af1553edd1f039ba16e7e3d34e04d53b3bac18814660e31cd0c48297ea4291ff86d0736b560123ebc63ecb62fa525829181d16a8dad15270d6672d7 languageName: node linkType: hard @@ -1343,10 +1343,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.15.7": - version: 18.15.7 - resolution: "@types/node@npm:18.15.7" - checksum: 08d1dd1898be10cd274955ed7f491bcab5b7e70ce66b6a1e996a582d5467f7517046b0d9c5f4e15871df94dd72d1ad9e7be236d2cff1a1450ec906d7fa3062d2 +"@types/node@npm:^18.15.11": + version: 18.15.11 + resolution: "@types/node@npm:18.15.11" + checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3 languageName: node linkType: hard @@ -1412,7 +1412,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^18.0.28": +"@types/react@npm:*": version: 18.0.28 resolution: "@types/react@npm:18.0.28" dependencies: @@ -1423,6 +1423,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.0.31": + version: 18.0.31 + resolution: "@types/react@npm:18.0.31" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: 6befbd5587e266905b50fd6bbd7c1cacd557bddf99e6a9862ca2f1d06df3dca71b9d485a37d010479730f021aab93b852d417c714de5efc2f41be0ff4c09b4db + languageName: node + linkType: hard + "@types/responselike@npm:^1.0.0": version: 1.0.0 resolution: "@types/responselike@npm:1.0.0" @@ -1464,14 +1475,14 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.56.0" +"@typescript-eslint/eslint-plugin@npm:^5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.57.0" dependencies: "@eslint-community/regexpp": ^4.4.0 - "@typescript-eslint/scope-manager": 5.56.0 - "@typescript-eslint/type-utils": 5.56.0 - "@typescript-eslint/utils": 5.56.0 + "@typescript-eslint/scope-manager": 5.57.0 + "@typescript-eslint/type-utils": 5.57.0 + "@typescript-eslint/utils": 5.57.0 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 @@ -1484,7 +1495,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2eed4a4ed8279950ad553252e8623e947ffdee39b0d677a13f6e4e2d863ea1cbc5d683ff189e55d0de6fd5a25afd72d3c3a9ab7ae417d5405a21ead907e1b154 + checksum: be13aa74ee6f15f0ae67781c625d9dcf3ce8a3feca2b125eef0cfee850b7f9f0cec23fc56a729ef25926298fe3ea51603ebeee2b93fc9b73fce1410638707177 languageName: node linkType: hard @@ -1499,20 +1510,20 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/parser@npm:5.56.0" +"@typescript-eslint/parser@npm:^5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/parser@npm:5.57.0" dependencies: - "@typescript-eslint/scope-manager": 5.56.0 - "@typescript-eslint/types": 5.56.0 - "@typescript-eslint/typescript-estree": 5.56.0 + "@typescript-eslint/scope-manager": 5.57.0 + "@typescript-eslint/types": 5.57.0 + "@typescript-eslint/typescript-estree": 5.57.0 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: eb25490290bd5e22f9c42603dedc0d2d8ee845553e3cf48ea377bd5dc22440d3463f8b84be637b6a2b37cd9ea56b21e4e43007a0a69998948d9c8965c03fe1aa + checksum: b7e8345631911f721591ba970fea5c888f0f3bf2e2ea2dbc3e5b0dc345c0776b62b92c534edfde1379b4b182958a421f35ac26d84705fe6ae7dd37aa675d9493 languageName: node linkType: hard @@ -1526,22 +1537,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/scope-manager@npm:5.56.0" +"@typescript-eslint/scope-manager@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/scope-manager@npm:5.57.0" dependencies: - "@typescript-eslint/types": 5.56.0 - "@typescript-eslint/visitor-keys": 5.56.0 - checksum: bacac255ee52148cee6622be2811c0d7e25419058b89f1a11f4c1303faef4535a0a1237549f9556ec1d7a297c640ce4357183a1a8465d72e1393b7d8fb43874b + "@typescript-eslint/types": 5.57.0 + "@typescript-eslint/visitor-keys": 5.57.0 + checksum: 4a851f23da2adbf6341b04c1e3f19fcb66415683f26805d3123725d18845bd4a150bd182de0a91279d5682f2568bb5dd831d4ad0bdb70f49d9ca7381cec4dd17 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/type-utils@npm:5.56.0" +"@typescript-eslint/type-utils@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/type-utils@npm:5.57.0" dependencies: - "@typescript-eslint/typescript-estree": 5.56.0 - "@typescript-eslint/utils": 5.56.0 + "@typescript-eslint/typescript-estree": 5.57.0 + "@typescript-eslint/utils": 5.57.0 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1549,7 +1560,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3dd1fcfadad18790b900a3d90f6617904adb6b0e2bd1e1edb6ebf239e1399865ca9098647405385feb4252d8b2b4577883e6fd3ef8d00bdd521d6070972d486b + checksum: 649d000edabfe4e567b8a384d0012c56396e40ce2123a78857d4b8da6bf2288627dc355745bd7d4a2877d4cc8a26e1d1dbfc422e6382ac3d3ab431b92eb5b852 languageName: node linkType: hard @@ -1560,10 +1571,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/types@npm:5.56.0" - checksum: 82ca11553bbb1bbfcaf7e7760b03c0d898940238dc002552c21af3e58f7d482c64c3c6cf0666521aff2a1e7b4b58bb6e4d9a00b1e4998a16b5039f5d288d003a +"@typescript-eslint/types@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/types@npm:5.57.0" + checksum: 79a100fb650965f63c01c20e6abd79ca0d2043c3a329b9fef89917d6b9ba3c0f946dca3f14f2975ee6349daadd6ce0e98fde3aafe4b710e5a27abe1adc590c85 languageName: node linkType: hard @@ -1585,12 +1596,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.56.0" +"@typescript-eslint/typescript-estree@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.57.0" dependencies: - "@typescript-eslint/types": 5.56.0 - "@typescript-eslint/visitor-keys": 5.56.0 + "@typescript-eslint/types": 5.57.0 + "@typescript-eslint/visitor-keys": 5.57.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1599,7 +1610,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ec3e85201786aa9adddba7cb834a9f330a7f55c729ee9ccf847dbdc2f7437b760f3774152ccad6d0aa48d13fd78df766c880e3a7ca42e01a20aba0e1a1ed61c5 + checksum: 648b88f88ea6cc293ec67b4c0f4f3c2bf733be7e0f2eee08aadbaec6939fd724a6c287decc336abbf67b9e366cc2c48f2e0e48d8302b533e783f798332a06e83 languageName: node linkType: hard @@ -1621,21 +1632,21 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/utils@npm:5.56.0" +"@typescript-eslint/utils@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/utils@npm:5.57.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.56.0 - "@typescript-eslint/types": 5.56.0 - "@typescript-eslint/typescript-estree": 5.56.0 + "@typescript-eslint/scope-manager": 5.57.0 + "@typescript-eslint/types": 5.57.0 + "@typescript-eslint/typescript-estree": 5.57.0 eslint-scope: ^5.1.1 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 413e8d4bf7023ee5ba4f695b62e796a1f94930bb92fe5aa0cee58f63b9837116c23f618825a9c671f610e50f5630188b6059b4ed6b05a2a3336f01d8e977becb + checksum: 461258e1194d24c5e642c65ba1afd612712fa8e617ac85cfbbe3dde2557fe4abadedbce19a6954ae0cccbfb92b8a09f38d65a3eedca0394861a5d1c4c893c5ed languageName: node linkType: hard @@ -1649,13 +1660,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.56.0": - version: 5.56.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.56.0" +"@typescript-eslint/visitor-keys@npm:5.57.0": + version: 5.57.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.57.0" dependencies: - "@typescript-eslint/types": 5.56.0 + "@typescript-eslint/types": 5.57.0 eslint-visitor-keys: ^3.3.0 - checksum: 568fda40134e153d7befb59b55698f7919ba780d2d3431d8745feabf2e0fbb8aa7a02173b3c467dd20a0f6594e5248a1f82bb25d6c37827716d77452e86cad29 + checksum: 77d53f74648e48bf1c6313cd60568c2b1539157ac13945f26204a54beb156666c24f3d033dd0db8ed5d1d4595ee63c072732b17132e4488b46763bf8fdcefa49 languageName: node linkType: hard @@ -1670,17 +1681,17 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/core@npm:^4.0.0-rc.40": - version: 4.0.0-rc.40 - resolution: "@yarnpkg/core@npm:4.0.0-rc.40" +"@yarnpkg/core@npm:^4.0.0-rc.42": + version: 4.0.0-rc.42 + resolution: "@yarnpkg/core@npm:4.0.0-rc.42" dependencies: "@arcanis/slice-ansi": ^1.1.1 "@types/semver": ^7.1.0 "@types/treeify": ^1.0.0 - "@yarnpkg/fslib": ^3.0.0-rc.40 - "@yarnpkg/libzip": ^3.0.0-rc.40 - "@yarnpkg/parsers": ^3.0.0-rc.40 - "@yarnpkg/shell": ^4.0.0-rc.40 + "@yarnpkg/fslib": ^3.0.0-rc.42 + "@yarnpkg/libzip": ^3.0.0-rc.42 + "@yarnpkg/parsers": ^3.0.0-rc.42 + "@yarnpkg/shell": ^4.0.0-rc.42 camelcase: ^5.3.1 chalk: ^3.0.0 ci-info: ^3.2.0 @@ -1699,84 +1710,84 @@ __metadata: treeify: ^1.1.0 tslib: ^2.4.0 tunnel: ^0.0.6 - checksum: 38a141f5e26355fd75e23c2a3afbe6bb79693ad914d263a75a2d212185ad2f987c740aea2e9f61fe360fcee666e9c56b961ffe57444e367acb7cc2ed77327127 + checksum: c7d4513453c996cbb5acf63044daa8547a21cec6f38b2c92683b3f7ea5bb50857bb0c9228d3a541dafe2551b771d15bb8bfb01636a27f11eacfe822c6f580024 languageName: node linkType: hard -"@yarnpkg/fslib@npm:^3.0.0-rc.40": - version: 3.0.0-rc.40 - resolution: "@yarnpkg/fslib@npm:3.0.0-rc.40" +"@yarnpkg/fslib@npm:^3.0.0-rc.42": + version: 3.0.0-rc.42 + resolution: "@yarnpkg/fslib@npm:3.0.0-rc.42" dependencies: tslib: ^2.4.0 - checksum: 8f36ade258a21ee9bec8621367dce68dab5d4e318863bd6b7585595f3697268f76fee5dd855c357ced31213d8ddbf2a2ab7a931d91699b295d60aa02433cc442 + checksum: 55f18e55a6a39f29584920e37fbf9cc1955093411f7e0e6e550c5771164f31a4b974c1d174fff8ac7b38675c149c3f9f9663ae666400f638d16d88b0fd0d052a languageName: node linkType: hard -"@yarnpkg/libzip@npm:^3.0.0-rc.40": - version: 3.0.0-rc.40 - resolution: "@yarnpkg/libzip@npm:3.0.0-rc.40" +"@yarnpkg/libzip@npm:^3.0.0-rc.42": + version: 3.0.0-rc.42 + resolution: "@yarnpkg/libzip@npm:3.0.0-rc.42" dependencies: "@types/emscripten": ^1.39.6 - "@yarnpkg/fslib": ^3.0.0-rc.40 + "@yarnpkg/fslib": ^3.0.0-rc.42 tslib: ^2.4.0 peerDependencies: - "@yarnpkg/fslib": ^3.0.0-rc.40 - checksum: eca50e5f56709a98111a77bede2e25da573668ad9bc98be01326c0ef1b7e47aac4de19896cc8f2a59f4f4175dfc6e9e307ee18c25facc32353d1209ab43b1c2e + "@yarnpkg/fslib": ^3.0.0-rc.42 + checksum: fd26e3d0969edcf51818c2d85c80101c3167c639339432646d037767d7e1236aa7e4af670a1694d70114e2823b7ec4ea46f64a1da700c2e65b49c2b922426385 languageName: node linkType: hard -"@yarnpkg/nm@npm:^4.0.0-rc.40": - version: 4.0.0-rc.40 - resolution: "@yarnpkg/nm@npm:4.0.0-rc.40" +"@yarnpkg/nm@npm:^4.0.0-rc.42": + version: 4.0.0-rc.42 + resolution: "@yarnpkg/nm@npm:4.0.0-rc.42" dependencies: - "@yarnpkg/core": ^4.0.0-rc.40 - "@yarnpkg/fslib": ^3.0.0-rc.40 - "@yarnpkg/pnp": ^4.0.0-rc.40 - checksum: d575264238be9dbd7c5dc435227e830f2d4a1a61c82292a3d6e1dd1f966d552e1acc02aa0f7a2fa60ffa551a3b0862fde320428d6fea20dd110fec4dd1394c7d + "@yarnpkg/core": ^4.0.0-rc.42 + "@yarnpkg/fslib": ^3.0.0-rc.42 + "@yarnpkg/pnp": ^4.0.0-rc.42 + checksum: d760c38191106ca591ef4a2c984f3fe4969346ef5d4b6bbb7caa83cef3ba342872daf55cadef5aee1d52592a2593b7b2625946325b33892f9c500af806997b18 languageName: node linkType: hard -"@yarnpkg/parsers@npm:^3.0.0-rc.40": - version: 3.0.0-rc.40 - resolution: "@yarnpkg/parsers@npm:3.0.0-rc.40" +"@yarnpkg/parsers@npm:^3.0.0-rc.42": + version: 3.0.0-rc.42 + resolution: "@yarnpkg/parsers@npm:3.0.0-rc.42" dependencies: js-yaml: ^3.10.0 tslib: ^2.4.0 - checksum: 64df0d8dad4cd43af5fcff758b0cfc47e7dc56e00eed87e3bd6ce8a9ea265c41fe758c1e01607e630bae46c9f8324ca853bced58be3d1c93492e125757ab7f30 + checksum: 147216f53d683ac2b0b4a68e6cda77b7194d70db5ad3b0b6863129b6f1e36054de5cd5c707707fc36921e110d3ac1cb6a0f51fc9e8d74a4a4123ec3b93d3951e languageName: node linkType: hard -"@yarnpkg/pnp@npm:^4.0.0-rc.40": - version: 4.0.0-rc.40 - resolution: "@yarnpkg/pnp@npm:4.0.0-rc.40" +"@yarnpkg/pnp@npm:^4.0.0-rc.42": + version: 4.0.0-rc.42 + resolution: "@yarnpkg/pnp@npm:4.0.0-rc.42" dependencies: "@types/node": ^18.11.11 - "@yarnpkg/fslib": ^3.0.0-rc.40 - checksum: ae680b0131027025cf22d35d41c9a72783aab0b4765fd73558834226a62154276da884a93bf7877d29dc5a696642c4d3999944dbb3d0743b4e3c6a4c71dc9855 + "@yarnpkg/fslib": ^3.0.0-rc.42 + checksum: bba47fc698cb385e4b86948c2dba9cd1541b163d747ae063fba02dbf735807ebe8c3fe8ed398ccadc76dd00df0752e2ccd15eda23d9f5f3704a18e4348ad26a3 languageName: node linkType: hard -"@yarnpkg/pnpify@npm:^4.0.0-rc.40": - version: 4.0.0-rc.40 - resolution: "@yarnpkg/pnpify@npm:4.0.0-rc.40" +"@yarnpkg/pnpify@npm:^4.0.0-rc.42": + version: 4.0.0-rc.42 + resolution: "@yarnpkg/pnpify@npm:4.0.0-rc.42" dependencies: - "@yarnpkg/core": ^4.0.0-rc.40 - "@yarnpkg/fslib": ^3.0.0-rc.40 - "@yarnpkg/nm": ^4.0.0-rc.40 + "@yarnpkg/core": ^4.0.0-rc.42 + "@yarnpkg/fslib": ^3.0.0-rc.42 + "@yarnpkg/nm": ^4.0.0-rc.42 clipanion: ^3.2.0-rc.10 tslib: ^2.4.0 bin: pnpify: ./lib/cli.js - checksum: 51ef0c5db61faedb0b35dd9d19e2ce539d3dcf4e2d17080c0c3f3bcc4570c4ea644c98b989872da275b9b68b04afb9541676433d1a2838774878b659f896bc72 + checksum: 17d6e30e1688a4b6abd59c102114ae0f48addec44a189cb50307bc0a8d243f3050a22e77f905736ccc8e62c4823496a7c4ca65faeaa902b3321f073c96f90ab1 languageName: node linkType: hard -"@yarnpkg/shell@npm:^4.0.0-rc.40": - version: 4.0.0-rc.40 - resolution: "@yarnpkg/shell@npm:4.0.0-rc.40" +"@yarnpkg/shell@npm:^4.0.0-rc.42": + version: 4.0.0-rc.42 + resolution: "@yarnpkg/shell@npm:4.0.0-rc.42" dependencies: - "@yarnpkg/fslib": ^3.0.0-rc.40 - "@yarnpkg/parsers": ^3.0.0-rc.40 + "@yarnpkg/fslib": ^3.0.0-rc.42 + "@yarnpkg/parsers": ^3.0.0-rc.42 chalk: ^3.0.0 clipanion: ^3.2.0-rc.10 cross-spawn: 7.0.3 @@ -1785,7 +1796,7 @@ __metadata: tslib: ^2.4.0 bin: shell: ./lib/cli.js - checksum: 0e136522ce5f157b38bdbb9633b9860cdfa06846cb6eafa5b04a64b790381cf4d946037669d4e975d4c4c9b5264f7f89e206dac5c82f01673ca5e479235d3c63 + checksum: f66db59b4e3f663477c44710447b70a49fd8c9483460f4c1e2971ecd9adc4b2adf075ce05b4cad483e06e35192ddf3cac4fff6765fed172772b8f9facbd4982d languageName: node linkType: hard @@ -1795,29 +1806,29 @@ __metadata: dependencies: "@emotion/react": ^11.10.6 "@emotion/styled": ^11.10.6 - "@msgpack/msgpack": ^2.8.0 + "@msgpack/msgpack": ^3.0.0-beta2 "@mui/icons-material": ^5.11.11 - "@mui/material": ^5.11.14 - "@remix-run/router": ^1.4.0 + "@mui/material": ^5.11.15 + "@remix-run/router": ^1.5.0 "@table-library/react-table-library": 4.1.0 "@types/lodash-es": ^4.17.7 "@types/mime-types": ^2 - "@types/node": ^18.15.7 - "@types/react": ^18.0.28 + "@types/node": ^18.15.11 + "@types/react": ^18.0.31 "@types/react-dom": ^18.0.11 "@types/react-router-dom": ^5.3.3 "@types/styled-components": ^5 - "@typescript-eslint/eslint-plugin": ^5.56.0 - "@typescript-eslint/parser": ^5.56.0 + "@typescript-eslint/eslint-plugin": ^5.57.0 + "@typescript-eslint/parser": ^5.57.0 "@vitejs/plugin-react-swc": ^3.2.0 - "@yarnpkg/pnpify": ^4.0.0-rc.40 + "@yarnpkg/pnpify": ^4.0.0-rc.42 async-validator: ^4.2.5 axios: ^1.3.4 - eslint: ^8.36.0 + eslint: ^8.37.0 eslint-config-airbnb: ^19.0.4 eslint-config-airbnb-typescript: ^17.0.0 eslint-config-prettier: ^8.8.0 - eslint-import-resolver-typescript: ^3.5.3 + eslint-import-resolver-typescript: ^3.5.4 eslint-plugin-deprecation: ^1.3.3 eslint-plugin-import: ^2.27.5 eslint-plugin-jsx-a11y: ^6.7.1 @@ -1835,13 +1846,13 @@ __metadata: react-dom: latest react-dropzone: ^14.2.3 react-icons: ^4.8.0 - react-router-dom: ^6.9.0 + react-router-dom: ^6.10.0 react-toastify: ^9.1.2 rollup-plugin-visualizer: ^5.9.0 sockette: ^2.0.6 - terser: ^5.16.6 - typesafe-i18n: ^5.24.2 - typescript: ^5.0.2 + terser: ^5.16.8 + typesafe-i18n: ^5.24.3 + typescript: ^5.0.3 vite: ^4.2.1 vite-plugin-minify: ^1.5.2 vite-plugin-svgr: ^2.4.0 @@ -2750,7 +2761,7 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.10.0": +"enhanced-resolve@npm:^5.12.0": version: 5.12.0 resolution: "enhanced-resolve@npm:5.12.0" dependencies: @@ -3045,21 +3056,21 @@ __metadata: languageName: node linkType: hard -"eslint-import-resolver-typescript@npm:^3.5.3": - version: 3.5.3 - resolution: "eslint-import-resolver-typescript@npm:3.5.3" +"eslint-import-resolver-typescript@npm:^3.5.4": + version: 3.5.4 + resolution: "eslint-import-resolver-typescript@npm:3.5.4" dependencies: debug: ^4.3.4 - enhanced-resolve: ^5.10.0 - get-tsconfig: ^4.2.0 - globby: ^13.1.2 - is-core-module: ^2.10.0 + enhanced-resolve: ^5.12.0 + get-tsconfig: ^4.5.0 + globby: ^13.1.3 + is-core-module: ^2.11.0 is-glob: ^4.0.3 - synckit: ^0.8.4 + synckit: ^0.8.5 peerDependencies: eslint: "*" eslint-plugin-import: "*" - checksum: 63b5f28bec5a29b1d3be33b79795441f7b0da54479e5c99a115877d9b70b2b7464c19a928b4ae7674a937b9ee8e7d4b1d30b7f5e6325c4c3aaa8c607bb175258 + checksum: 6d778645279f5525d03d6d85dd5cd01972a69df0fcb51b3ea2e7563a8803b9f0a4ddd6413e48bb9c34388a1ff555adab2781c86664689d40bbb6e017f0243fbf languageName: node linkType: hard @@ -3234,14 +3245,21 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.36.0": - version: 8.36.0 - resolution: "eslint@npm:8.36.0" +"eslint-visitor-keys@npm:^3.4.0": + version: 3.4.0 + resolution: "eslint-visitor-keys@npm:3.4.0" + checksum: 33159169462d3989321a1ec1e9aaaf6a24cc403d5d347e9886d1b5bfe18ffa1be73bdc6203143a28a606b142b1af49787f33cff0d6d0813eb5f2e8d2e1a6043c + languageName: node + linkType: hard + +"eslint@npm:^8.37.0": + version: 8.37.0 + resolution: "eslint@npm:8.37.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.4.0 - "@eslint/eslintrc": ^2.0.1 - "@eslint/js": 8.36.0 + "@eslint/eslintrc": ^2.0.2 + "@eslint/js": 8.37.0 "@humanwhocodes/config-array": ^0.11.8 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -3252,8 +3270,8 @@ __metadata: doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 eslint-scope: ^7.1.1 - eslint-visitor-keys: ^3.3.0 - espree: ^9.5.0 + eslint-visitor-keys: ^3.4.0 + espree: ^9.5.1 esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 @@ -3280,18 +3298,18 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: e9a961fc3b3de5cff5a1cb2c92eeffaa7e155a715489e30b3e1e76f186bd1255e0481e09564f2094733c0b1dbd3453499fb72ae7c043c83156e11e6d965b2304 + checksum: 80f3d5cdce2d671f4794e392d234a78d039c347673defb0596268bd481e8f30a53d93c01ff4f66a546c87d97ab4122c0e9cafe1371f87cb03cee6b7d5aa97595 languageName: node linkType: hard -"espree@npm:^9.5.0": - version: 9.5.0 - resolution: "espree@npm:9.5.0" +"espree@npm:^9.5.1": + version: 9.5.1 + resolution: "espree@npm:9.5.1" dependencies: acorn: ^8.8.0 acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.3.0 - checksum: a7f110aefb6407e0d3237aa635ab3cea87106ae63748dd23c67031afccc640d04c4209fca2daf16e2233c82efb505faead0fb84097478fd9cc6e8f8dd80bf99d + eslint-visitor-keys: ^3.4.0 + checksum: cdf6e43540433d917c4f2ee087c6e987b2063baa85a1d9cdaf51533d78275ebd5910c42154e7baf8e3e89804b386da0a2f7fad2264d8f04420e7506bf87b3b88 languageName: node linkType: hard @@ -3613,10 +3631,10 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.2.0": - version: 4.4.0 - resolution: "get-tsconfig@npm:4.4.0" - checksum: e193558b4f0c84c81ae9688cf5b9950dc0b341e44f91b002713fd0c37cfb73108e1cd9998ed540bcc423f193fde32cc58a15e99dd469f5158a2eb4a148611176 +"get-tsconfig@npm:^4.5.0": + version: 4.5.0 + resolution: "get-tsconfig@npm:4.5.0" + checksum: 687ee2bd69a5a07db2e2edeb4d6c41c3debb38f6281a66beb643e3f5b520252e27fcbbb5702bdd9a5f05dcf8c1d2e0150a4d8a960ad75cbdea74e06a51e91b02 languageName: node linkType: hard @@ -3711,7 +3729,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.2": +"globby@npm:^13.1.3": version: 13.1.3 resolution: "globby@npm:13.1.3" dependencies: @@ -4092,7 +4110,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.10.0, is-core-module@npm:^2.11.0, is-core-module@npm:^2.9.0": +"is-core-module@npm:^2.11.0, is-core-module@npm:^2.9.0": version: 2.11.0 resolution: "is-core-module@npm:2.11.0" dependencies: @@ -5390,27 +5408,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.9.0": - version: 6.9.0 - resolution: "react-router-dom@npm:6.9.0" +"react-router-dom@npm:^6.10.0": + version: 6.10.0 + resolution: "react-router-dom@npm:6.10.0" dependencies: - "@remix-run/router": 1.4.0 - react-router: 6.9.0 + "@remix-run/router": 1.5.0 + react-router: 6.10.0 peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 4d593491ab8db5611feda70002c62902baebb84d5c1c5e5b6172496f31f91130deee132bf4240dea634a88cb86c76d6da348f15b9cd5e5197be455efd88edf72 + checksum: d048d8cc66e5aec782bd675097d6bf0e5f867f3f0539bff9acdc4a314b5e0e34093944762960ca0977a54c6255272edd262231242b18c4e260d68df6b5288464 languageName: node linkType: hard -"react-router@npm:6.9.0": - version: 6.9.0 - resolution: "react-router@npm:6.9.0" +"react-router@npm:6.10.0": + version: 6.10.0 + resolution: "react-router@npm:6.10.0" dependencies: - "@remix-run/router": 1.4.0 + "@remix-run/router": 1.5.0 peerDependencies: react: ">=16.8" - checksum: b2a5f42e042bee7a7f116ca7817b0e58359e5353d84887c9fe7a633d7490c03b1e0ae37cd01830c2a381e3d1e7d501bb4751e53cc3d491e25f36582d3f6e0546 + checksum: c9fce46147c04257d7d6fa1f5bbfac96c5fdd0b15f26918bd12b2e5fe9143977c5a4452272f9b85795a22e29ec105a60d0bbe036118efc52b383d163cd8829ab languageName: node linkType: hard @@ -6100,7 +6118,7 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.8.4": +"synckit@npm:^0.8.5": version: 0.8.5 resolution: "synckit@npm:0.8.5" dependencies: @@ -6131,7 +6149,7 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.10.0, terser@npm:^5.16.6": +"terser@npm:^5.10.0": version: 5.16.6 resolution: "terser@npm:5.16.6" dependencies: @@ -6145,6 +6163,20 @@ __metadata: languageName: node linkType: hard +"terser@npm:^5.16.8": + version: 5.16.8 + resolution: "terser@npm:5.16.8" + dependencies: + "@jridgewell/source-map": ^0.3.2 + acorn: ^8.5.0 + commander: ^2.20.0 + source-map-support: ~0.5.20 + bin: + terser: bin/terser + checksum: f4a3ef4848a71f74f637c009395cf5a28660b56237fb8f13532cecfb24d6263e2dfbc1a511a11a94568988898f79cdcbecb9a4d8e104db35a0bea9639b70a325 + languageName: node + linkType: hard + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -6295,34 +6327,34 @@ __metadata: languageName: node linkType: hard -"typesafe-i18n@npm:^5.24.2": - version: 5.24.2 - resolution: "typesafe-i18n@npm:5.24.2" +"typesafe-i18n@npm:^5.24.3": + version: 5.24.3 + resolution: "typesafe-i18n@npm:5.24.3" peerDependencies: typescript: ">=3.5.1" bin: typesafe-i18n: cli/typesafe-i18n.mjs - checksum: c87b86ca2d310d48ddae3ccfd65059a4edc3c9129fd7c86a266cff38a22ff54fa290108da25f0c8b0335aac5b1cedb2d33ecc11e80139170a12dc8b4a03dd7df + checksum: 4bb6f9ca388a1d8e8af76887c0dfb6c6e71251c70c7d45a7d6257ce5621c027f93c2fca8e0b587207ceab898a4861d5a9d21c7cd932dd44eb2c57698425070d0 languageName: node linkType: hard -"typescript@npm:^5.0.2": - version: 5.0.2 - resolution: "typescript@npm:5.0.2" +"typescript@npm:^5.0.3": + version: 5.0.3 + resolution: "typescript@npm:5.0.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: bef1dcd166acfc6934b2ec4d72f93edb8961a5fab36b8dd2aaf6f4f4cd5c0210f2e0850aef4724f3b4913d5aef203a94a28ded731b370880c8bcff7e4ff91fc1 + checksum: 3cce0576d218cb4277ff8b6adfef1a706e9114a98b4261a38ad658a7642f1b274a8396394f6cbff8c0ba852996d7ed2e233e9b8431d5d55ac7c2f6fea645af02 languageName: node linkType: hard -"typescript@patch:typescript@^5.0.2#~builtin": - version: 5.0.2 - resolution: "typescript@patch:typescript@npm%3A5.0.2#~builtin::version=5.0.2&hash=1f5320" +"typescript@patch:typescript@^5.0.3#~builtin": + version: 5.0.3 + resolution: "typescript@patch:typescript@npm%3A5.0.3#~builtin::version=5.0.3&hash=1f5320" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: bdbf3d0aac0d6cf010fbe0536753dc19f278eb4aba88140dcd25487dfe1c56ca8b33abc0dcd42078790a939b08ebc4046f3e9bb961d77d3d2c3cfa9829da4d53 + checksum: 9ec0a8eed38d46cc2c8794555b7674e413604c56c159f71b8ff21ce7f17334a44127a68724cb2ef8221ff3b19369f8f05654e8a5266621d7d962aeed889bd630 languageName: node linkType: hard From 36d5df65b880fb9431ed899bcfc500bd98e416fd Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 31 Mar 2023 16:49:30 +0200 Subject: [PATCH 2/5] env for asymetric partitions (loader) --- esp32_asym_partition_4M.csv | 6 ++++++ platformio.ini | 27 ++++++++++++++++++++------- scripts/build_interface.py | 1 + 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 esp32_asym_partition_4M.csv diff --git a/esp32_asym_partition_4M.csv b/esp32_asym_partition_4M.csv new file mode 100644 index 000000000..f87875c3a --- /dev/null +++ b/esp32_asym_partition_4M.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, , 0x2000, +app1, app, ota_1, , 0x140000, +app0, app, ota_0, , 0x2A0000, +spiffs, data, spiffs, , 64K, \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index cb2e485a4..02ab00239 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,9 +40,9 @@ unbuild_flags = ${common.core_unbuild_flags} [espressi32_base] -; platform = espressif32 +platform = espressif32 ; platform = espressif32@5.3.0 -platform = espressif32@5.2.0 +; platform = espressif32@5.2.0 framework = arduino [env] @@ -62,7 +62,8 @@ check_flags = ; build for GitHub Actions CI ; the Web interface is built seperately [env:ci] -extends = espressi32_base +platform = espressif32@5.2.0 +framework = arduino extra_scripts = scripts/rename_fw.py board = esp32dev board_build.partitions = esp32_partition_4M.csv @@ -71,7 +72,8 @@ build_flags = ${common.build_flags} build_unflags = ${common.unbuild_flags} [env:esp32_4M] -extends = espressi32_base +platform = espressif32@5.2.0 +framework = arduino extra_scripts = pre:scripts/build_interface.py scripts/rename_fw.py @@ -81,6 +83,17 @@ board_build.partitions = esp32_partition_4M.csv build_flags = ${common.build_flags} -Os build_unflags = ${common.unbuild_flags} +[env:esp32_4M+] +extends = espressi32_base +extra_scripts = + pre:scripts/build_interface.py + scripts/rename_fw.py +board = esp32dev +board_upload.flash_size = 4MB +board_build.partitions = esp32_asym_partition_4M.csv +build_flags = ${common.build_flags} +build_unflags = ${common.unbuild_flags} + [env:esp32_16M] extends = espressi32_base extra_scripts = @@ -99,7 +112,7 @@ extra_scripts = scripts/rename_fw.py board = lolin_c3_mini board_upload.flash_size = 4MB -board_build.partitions = esp32_partition_4M.csv +board_build.partitions = esp32_asym_partition_4M.csv build_flags = ${common.build_flags} build_unflags = ${common.unbuild_flags} @@ -112,7 +125,7 @@ extra_scripts = scripts/rename_fw.py board = lolin_c3_mini board_upload.flash_size = 4MB -board_build.partitions = esp32_partition_4M.csv +board_build.partitions = esp32_asym_partition_4M.csv build_flags = ${common.build_flags} -DBOARD_C3_MINI_V1 build_unflags = ${common.unbuild_flags} @@ -123,7 +136,7 @@ extra_scripts = scripts/rename_fw.py board = lolin_s2_mini board_upload.flash_size = 4MB -board_build.partitions = esp32_partition_4M.csv +board_build.partitions = esp32_asym_partition_4M.csv build_flags = ${common.build_flags} build_unflags = ${common.unbuild_flags} diff --git a/scripts/build_interface.py b/scripts/build_interface.py index 6fd6e215b..608a2ab7c 100644 --- a/scripts/build_interface.py +++ b/scripts/build_interface.py @@ -39,6 +39,7 @@ def buildWeb(): text = r.read().replace("Locales = 'pl'", "Locales = 'en'") with open("./src/i18n/i18n-util.ts", "w") as w: w.write(text) + print("Setting locale to 'en'") env.Execute("yarn run build") buildPath = Path("build") From fa50846a05588de33decc87929bd0b42103bf4df Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 31 Mar 2023 16:50:49 +0200 Subject: [PATCH 3/5] add own entities read from ems-bus with free factor --- .../framework/system/GeneralFileUpload.tsx | 21 + interface/src/i18n/de/index.ts | 4 +- interface/src/i18n/en/index.ts | 4 +- interface/src/i18n/fr/index.ts | 4 +- interface/src/i18n/nl/index.ts | 4 +- interface/src/i18n/no/index.ts | 4 +- interface/src/i18n/pl/index.ts | 4 +- interface/src/i18n/sv/index.ts | 4 +- interface/src/i18n/tr/index.ts | 4 +- interface/src/project/DeviceIcon.tsx | 5 +- interface/src/project/Settings.tsx | 3 + .../src/project/SettingsCustomization.tsx | 1 + interface/src/project/SettingsEntities.tsx | 491 ++++++++++++++++++ interface/src/project/api.ts | 15 +- interface/src/project/types.ts | 24 + interface/src/project/validators.ts | 53 +- src/command.cpp | 4 + src/emsdevice.cpp | 5 + src/emsdevice.h | 1 + src/emsesp.cpp | 19 +- src/emsesp.h | 2 + src/locale_common.h | 1 + src/locale_translations.h | 2 + src/system.cpp | 3 + src/web/WebAPIService.cpp | 13 + src/web/WebAPIService.h | 2 + src/web/WebDataService.cpp | 52 ++ src/web/WebEntityService.cpp | 429 +++++++++++++++ src/web/WebEntityService.h | 74 +++ 29 files changed, 1232 insertions(+), 20 deletions(-) create mode 100644 interface/src/project/SettingsEntities.tsx create mode 100644 src/web/WebEntityService.cpp create mode 100644 src/web/WebEntityService.h diff --git a/interface/src/framework/system/GeneralFileUpload.tsx b/interface/src/framework/system/GeneralFileUpload.tsx index 8edc79442..79cce8622 100644 --- a/interface/src/framework/system/GeneralFileUpload.tsx +++ b/interface/src/framework/system/GeneralFileUpload.tsx @@ -67,6 +67,19 @@ const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { } }; + const downloadEntities = async () => { + try { + const response = await EMSESP.getEntities(); + if (response.status !== 200) { + toast.error(LL.PROBLEM_LOADING()); + } else { + saveFile(response.data, 'entities'); + } + } catch (error) { + toast.error(extractErrorMessage(error, LL.PROBLEM_LOADING())); + } + }; + const downloadSchedule = async () => { try { const response = await EMSESP.getSchedule(); @@ -125,6 +138,14 @@ const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { > {LL.CUSTOMIZATIONS()} + {LL.DOWNLOAD_SCHEDULE_TEXT()}{' '} diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index c3140937b..db5fbcbc4 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -318,7 +318,9 @@ const de: Translation = { SCHEDULE_SAVED: 'Plan gespeichert', SCHEDULE_TIMER_1: 'beim Start', SCHEDULE_TIMER_2: 'jede Minute', - SCHEDULE_TIMER_3: 'jede Stunde' + SCHEDULE_TIMER_3: 'jede Stunde', + CUSTOM_ENTITIES: 'Individuelle Entitäten', + ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 0cd8899b9..3f0b829f9 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -318,7 +318,9 @@ const en: Translation = { SCHEDULE_SAVED: 'Schedule updated', SCHEDULE_TIMER_1: 'on startup', SCHEDULE_TIMER_2: 'every minute', - SCHEDULE_TIMER_3: 'every hour' + SCHEDULE_TIMER_3: 'every hour', + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 8a4b9a8a6..aa91b2ca3 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -318,7 +318,9 @@ const fr: Translation = { SCHEDULE_SAVED: 'Schedule updated', // TODO translate SCHEDULE_TIMER_1: 'on startup', // TODO translate SCHEDULE_TIMER_2: 'every minute', // TODO translate - SCHEDULE_TIMER_3: 'every hour' // TODO translate + SCHEDULE_TIMER_3: 'every hour', // TODO translate + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default fr; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index e3c46292f..ff0257861 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -318,7 +318,9 @@ const nl: Translation = { SCHEDULE_SAVED: 'Schedule updated', // TODO translate SCHEDULE_TIMER_1: 'on startup', // TODO translate SCHEDULE_TIMER_2: 'every minute', // TODO translate - SCHEDULE_TIMER_3: 'every hour' // TODO translate + SCHEDULE_TIMER_3: 'every hour', // TODO translate + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index bab6505f8..ac7dfe79b 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -318,7 +318,9 @@ const no: Translation = { SCHEDULE_SAVED: 'Planlegger er oppdatert', SCHEDULE_TIMER_1: 'ved oppstart', SCHEDULE_TIMER_2: 'hvert minutt', - SCHEDULE_TIMER_3: 'hver time' + SCHEDULE_TIMER_3: 'hver time', + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 856d2b31d..5f1fff143 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -318,7 +318,9 @@ const pl: BaseTranslation = { SCHEDULE_SAVED: 'Harmonogram został uaktualniony.', SCHEDULE_TIMER_1: 'przy starcie', SCHEDULE_TIMER_2: 'co minutę', - SCHEDULE_TIMER_3: 'co godzinę' + SCHEDULE_TIMER_3: 'co godzinę', + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default pl; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 5fa2ee34e..e2f21039b 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -318,7 +318,9 @@ const sv: Translation = { SCHEDULE_SAVED: 'Schedule updated', // TODO translate SCHEDULE_TIMER_1: 'on startup', // TODO translate SCHEDULE_TIMER_2: 'every minute', // TODO translate - SCHEDULE_TIMER_3: 'every hour' // TODO translate + SCHEDULE_TIMER_3: 'every hour', // TODO translate + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 6947c2983..ddbb41cb6 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -318,7 +318,9 @@ const tr: Translation = { SCHEDULE_SAVED: 'Schedule updated', // TODO translate SCHEDULE_TIMER_1: 'on startup', // TODO translate SCHEDULE_TIMER_2: 'every minute', // TODO translate - SCHEDULE_TIMER_3: 'every hour' // TODO translate + SCHEDULE_TIMER_3: 'every hour', // TODO translate + CUSTOM_ENTITIES: 'Custom entities', + ENTITIES_HELP_1: 'Fetch custom entities from the EMS-bus' }; export default tr; diff --git a/interface/src/project/DeviceIcon.tsx b/interface/src/project/DeviceIcon.tsx index baf785a42..d199db075 100644 --- a/interface/src/project/DeviceIcon.tsx +++ b/interface/src/project/DeviceIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import { CgSmartHomeBoiler } from 'react-icons/cg'; import { FaSolarPanel } from 'react-icons/fa'; -import { MdThermostatAuto, MdOutlineSensors } from 'react-icons/md'; +import { MdThermostatAuto, MdOutlineSensors, MdOutlineExtension } from 'react-icons/md'; import { GiHeatHaze } from 'react-icons/gi'; import { TiFlowSwitch } from 'react-icons/ti'; import { VscVmConnect } from 'react-icons/vsc'; @@ -31,6 +31,7 @@ const enum DeviceType { PUMP, GENERIC, HEATSOURCE, + CUSTOM, UNKNOWN } @@ -61,6 +62,8 @@ const DeviceIcon: FC = ({ type_id }) => { return ; case DeviceType.PUMP: return ; + case DeviceType.CUSTOM: + return ; default: return null; } diff --git a/interface/src/project/Settings.tsx b/interface/src/project/Settings.tsx index ca26a6583..1b5a62c89 100644 --- a/interface/src/project/Settings.tsx +++ b/interface/src/project/Settings.tsx @@ -10,6 +10,7 @@ import { useI18nContext } from 'i18n/i18n-react'; import SettingsApplication from './SettingsApplication'; import SettingsCustomization from './SettingsCustomization'; import SettingsScheduler from './SettingsScheduler'; +import SettingsEntities from './SettingsEntities'; const Settings: FC = () => { const { LL } = useI18nContext(); @@ -23,11 +24,13 @@ const Settings: FC = () => { + } /> } /> } /> + } /> } /> diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index 00e2b5711..344d8abae 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -245,6 +245,7 @@ const SettingsCustomization: FC = () => { if (devices) { const selected_device = parseInt(event.target.value, 10); setSelectedDevice(selected_device); + setNumChanges(0); fetchDeviceEntities(devices?.devices[selected_device].i); setRestartNeeded(false); } diff --git a/interface/src/project/SettingsEntities.tsx b/interface/src/project/SettingsEntities.tsx new file mode 100644 index 000000000..588888119 --- /dev/null +++ b/interface/src/project/SettingsEntities.tsx @@ -0,0 +1,491 @@ +import { FC, useState, useEffect, useCallback } from 'react'; +import { unstable_useBlocker as useBlocker } from 'react-router-dom'; + +import { + Button, + Typography, + Box, + Grid, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + TextField, + MenuItem, + InputAdornment +} from '@mui/material'; + +import { useTheme } from '@table-library/react-table-library/theme'; +import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table'; + +import { toast } from 'react-toastify'; + +import RemoveIcon from '@mui/icons-material/RemoveCircleOutline'; +import WarningIcon from '@mui/icons-material/Warning'; +import CancelIcon from '@mui/icons-material/Cancel'; +import DoneIcon from '@mui/icons-material/Done'; +import AddIcon from '@mui/icons-material/Add'; + +import { ValidatedTextField, ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components'; + +import { DeviceValueUOM_s, EntityItem } from './types'; +import { extractErrorMessage, updateValue } from 'utils'; + +import { validate } from 'validators'; +import { entityItemValidation } from './validators'; + +import { useI18nContext } from 'i18n/i18n-react'; + +import { ValidateFieldsError } from 'async-validator'; + +import * as EMSESP from './api'; + +const SettingsEntities: FC = () => { + const { LL, locale } = useI18nContext(); + + const [numChanges, setNumChanges] = useState(0); + const blocker = useBlocker(numChanges !== 0); + + const emptyEntity = { + device_id: 8, + type_id: 2, + offset: 0, + factor: 1, + uom: 0, + val_type: 2, + name: 'name', + deleted: false + }; + const [entity, setEntity] = useState([emptyEntity]); + const [entityItem, setEntityItem] = useState(); + const [errorMessage, setErrorMessage] = useState(); + const [creating, setCreating] = useState(false); + + const [fieldErrors, setFieldErrors] = useState(); + + useEffect(() => { + setNumChanges(getNumChanges()); + }); + + const entity_theme = useTheme({ + Table: ` + --data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) 80px 80px 80px 80px; + `, + BaseRow: ` + font-size: 14px; + .td { + height: 32px; + } + `, + BaseCell: ` + &:nth-of-type(2) { + text-align: center; + } + &:nth-of-type(3) { + text-align: center; + } + &:nth-of-type(4) { + text-align: center; + } + &:nth-of-type(5) { + text-align: right; + } + `, + HeaderRow: ` + text-transform: uppercase; + background-color: black; + color: #90CAF9; + .th { + border-bottom: 1px solid #565656; + height: 36px; + } + `, + Row: ` + background-color: #1e1e1e; + position: relative; + cursor: pointer; + .td { + border-top: 1px solid #565656; + border-bottom: 1px solid #565656; + } + &:hover .td { + border-top: 1px solid #177ac9; + border-bottom: 1px solid #177ac9; + } + &:nth-of-type(odd) .td { + background-color: #303030; + } + ` + }); + + const fetchEntities = useCallback(async () => { + try { + const response = await EMSESP.readEntities(); + setOriginalEntity(response.data.entity); + } catch (error) { + setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); + } + }, [LL]); + + useEffect(() => { + fetchEntities(); + }, [fetchEntities]); + + const setOriginalEntity = (data: EntityItem[]) => { + setEntity( + data.map((ei) => ({ + ...ei, + o_device_id: ei.device_id, + o_type_id: ei.type_id, + o_offset: ei.offset, + o_factor: ei.factor, + o_uom: ei.uom, + o_val_type: ei.val_type, + o_name: ei.name, + o_deleted: ei.deleted + })) + ); + }; + + function hasEntityChanged(ei: EntityItem) { + return ( + ei.device_id !== ei.o_device_id || + ei.type_id !== ei.o_type_id || + ei.name !== ei.o_name || + ei.offset !== ei.o_offset || + ei.uom !== ei.o_uom || + ei.factor !== ei.o_factor || + ei.val_type !== ei.o_val_type || + ei.deleted !== ei.o_deleted + ); + } + + const getNumChanges = () => { + if (!entity) { + return 0; + } + return entity.filter((ei) => hasEntityChanged(ei)).length; + }; + + const saveEntity = async () => { + if (entity) { + try { + const response = await EMSESP.writeEntities({ + entity: entity + .filter((ei) => !ei.deleted) + .map((condensed_ei) => { + return { + device_id: condensed_ei.device_id, + type_id: condensed_ei.type_id, + offset: condensed_ei.offset, + factor: condensed_ei.factor, + val_type: condensed_ei.val_type, + uom: condensed_ei.uom, + name: condensed_ei.name + }; + }) + }); + if (response.status === 200) { + toast.success(LL.SUCCESS()); + } else { + toast.error(LL.PROBLEM_UPDATING()); + } + } catch (error) { + toast.error(extractErrorMessage(error, LL.PROBLEM_UPDATING())); + } + setOriginalEntity(entity); + } + }; + + const editEntityItem = (ei: EntityItem) => { + setCreating(false); + setEntityItem(ei); + }; + + const addEntityItem = () => { + setCreating(true); + setEntityItem({ + device_id: 8, + type_id: 2, + offset: 0, + factor: 1, + val_type: 2, + uom: 0, + name: 'name', + deleted: false + }); + }; + + const updateEntityItem = () => { + if (entityItem) { + setEntity([...entity.filter((ei) => creating || ei.o_name !== entityItem.o_name), entityItem]); + } + setEntityItem(undefined); + }; + + function formatValue(value: any, uom: number) { + if (value === undefined) { + return ''; + } + if (uom === 0) { + return new Intl.NumberFormat().format(value); + } + return new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom]; + } + + function showHex(value: string, digit: number) { + if (digit === 4) { + return '0x' + ('000' + value).slice(-4); + } + return '0x' + ('0' + value).slice(-2); + } + + const renderEntity = () => { + if (!entity) { + return ; + } + + return ( + !ei.deleted).sort((a, b) => a.name.localeCompare(b.time)) }} + theme={entity_theme} + layout={{ custom: true }} + > + {(tableList: any) => ( + <> +
+ + {LL.NAME(0)} + Device ID + Type ID + Offset + {LL.VALUE()} + +
+ + {tableList.map((ei: EntityItem) => ( + editEntityItem(ei)}> + {ei.name} + {showHex(ei.device_id, 2)} + {showHex(ei.type_id, 4)} + {ei.offset} + {formatValue(ei.value, ei.uom)} + + ))} + + + )} +
+ ); + }; + + const removeEntityItem = (ei: EntityItem) => { + ei.deleted = true; + setEntityItem(ei); + updateEntityItem(); + }; + + const validateEntityItem = async () => { + if (entityItem) { + try { + setFieldErrors(undefined); + await validate(entityItemValidation(entity, entityItem), entityItem); + updateEntityItem(); + } catch (errors: any) { + setFieldErrors(errors); + } + } + }; + + const closeDialog = () => { + setEntityItem(undefined); + setFieldErrors(undefined); + }; + + const renderEditEntity = () => { + if (entityItem) { + return ( + closeDialog()}> + + {creating ? LL.ADD(1) + ' ' + LL.NEW() : LL.EDIT()} {LL.CUSTOM_ENTITIES()} + + + + + + + + + + + + 0x + }} + /> + + + 0x + }} + /> + + + + + + + BOOL + INT + UINT + SHORT + USHORT + ULONG + TIME + + + {entityItem.val_type !== 0 && ( + <> + + + + + + {DeviceValueUOM_s.map((val, i) => ( + + {val} + + ))} + + + + )} + + + + {!creating && ( + + + + )} + + + + + ); + } + }; + + return ( + + {blocker ? : null} + + {LL.ENTITIES_HELP_1()} + + {renderEntity()} + {renderEditEntity()} + + + {numChanges !== 0 && ( + + + + + )} + + + + + + + + + ); +}; + +export default SettingsEntities; diff --git a/interface/src/project/api.ts b/interface/src/project/api.ts index 586a632fa..ab394168a 100644 --- a/interface/src/project/api.ts +++ b/interface/src/project/api.ts @@ -17,7 +17,8 @@ import { WriteSensor, WriteAnalog, SensorData, - Schedule + Schedule, + Entities } from './types'; export function restart(): AxiosPromise { @@ -96,6 +97,18 @@ export function getCustomizations(): AxiosPromise { return AXIOS.get('/getCustomizations'); } +export function getEntities(): AxiosPromise { + return AXIOS.get('/getEntities'); +} + +export function readEntities(): AxiosPromise { + return AXIOS.get('/entity'); +} + +export function writeEntities(entities: Entities): AxiosPromise { + return AXIOS.post('/entity', entities); +} + export function getSchedule(): AxiosPromise { return AXIOS.get('/getSchedule'); } diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index 53edba81f..2989614eb 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -337,3 +337,27 @@ export enum ScheduleFlag { SCHEDULE_SAT = 64, SCHEDULE_TIMER = 128 } + +export interface EntityItem { + name: string; + device_id: string; + type_id: string; + offset: number; + factor: number; + uom: number; + val_type: number; + value?: number; + o_name?: string; + o_device_id?: string; + o_type_id?: string; + o_offset?: number; + o_factor?: number; + o_uom?: number; + o_val_type?: number; + deleted?: boolean; // optional + o_deleted?: boolean; +} + +export interface Entities { + entity: EntityItem[]; +} diff --git a/interface/src/project/validators.ts b/interface/src/project/validators.ts index 7c2900572..300dff467 100644 --- a/interface/src/project/validators.ts +++ b/interface/src/project/validators.ts @@ -1,6 +1,6 @@ import Schema, { InternalRuleItem } from 'async-validator'; import { IP_OR_HOSTNAME_VALIDATOR } from 'validators/shared'; -import { Settings, ScheduleItem } from './types'; +import { Settings, ScheduleItem, EntityItem } from './types'; export const GPIO_VALIDATOR = { validator(rule: InternalRuleItem, value: number, callback: (error?: string) => void) { @@ -101,12 +101,47 @@ export const schedulerItemValidation = (schedule: ScheduleItem[], scheduleItem: ] }); -export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) => ({ - validator(rule: InternalRuleItem, name: string, callback: (error?: string) => void) { - if (name && o_name && o_name !== name && schedule.find((si) => si.name === name)) { - callback('Name already in use'); - } else { - callback(); + export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) => ({ + validator(rule: InternalRuleItem, name: string, callback: (error?: string) => void) { + if (name && o_name && o_name !== name && schedule.find((si) => si.name === name)) { + callback('Name already in use'); + } else { + callback(); + } } - } -}); + }); + + export const entityItemValidation = (entity: EntityItem[], entityItem: EntityItem) => + new Schema({ + name: [ + { required: true, message: 'Name is required' }, + { + type: 'string', + pattern: /^[a-zA-Z0-9_\\.]{1,15}$/, + message: "Must be <15 characters: alpha numeric, '_' or '.'" + }, + ...[uniqueEntityNameValidator(entity, entityItem.o_name)] + ], + device_id: [ + { required: true, message: 'Device_id is required' }, + { type: 'string', pattern: /^[A-F0-9]{1,2}$/, message: 'Must be a hex number' } + ], + type_id: [ + { required: true, message: 'Type_id is required' }, + { type: 'string', pattern: /^[A-F0-9]{1,4}$/, message: 'Must be a hex number' } + ], + offset: [ + { required: true, message: 'Offset is required' }, + { type: 'number', min: 0, max: 255, message: 'Must be between 0 and 255' } + ] + }); + + export const uniqueEntityNameValidator = (entity: EntityItem[], o_name?: string) => ({ + validator(rule: InternalRuleItem, name: string, callback: (error?: string) => void) { + if (name && o_name && o_name !== name && entity.find((ei) => ei.name === name)) { + callback('Name already in use'); + } else { + callback(); + } + } + }); diff --git a/src/command.cpp b/src/command.cpp index 1649b2fcd..d75d58ebb 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -539,6 +539,10 @@ bool Command::device_has_commands(const uint8_t device_type) { return EMSESP::webSchedulerService.has_commands(); } + if (device_type == EMSdevice::DeviceType::CUSTOM) { + return (EMSESP::webEntityService.count_entities() != 0); + } + if (device_type == EMSdevice::DeviceType::DALLASSENSOR) { return (EMSESP::dallassensor_.have_sensors()); } diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 7d9e0b416..f7bd9d2e8 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -135,6 +135,8 @@ const char * EMSdevice::device_type_2_device_name(const uint8_t device_type) { return F_(pump); case DeviceType::HEATSOURCE: return F_(heatsource); + case DeviceType::CUSTOM: + return F_(custom); default: return Helpers::translated_word(FL_(unknown), true); } @@ -229,6 +231,9 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) { if (!strcmp(lowtopic, F_(heatsource))) { return DeviceType::HEATSOURCE; } + if (!strcmp(lowtopic, F_(custom))) { + return DeviceType::CUSTOM; + } return DeviceType::UNKNOWN; } diff --git a/src/emsdevice.h b/src/emsdevice.h index e2c1a8ad4..5e2729e88 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -336,6 +336,7 @@ class EMSdevice { PUMP, GENERIC, HEATSOURCE, + CUSTOM, UNKNOWN }; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index f6bf067b9..3f2a8de16 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -32,11 +32,13 @@ ESP8266React EMSESP::esp8266React(&webServer, &dummyFS); WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager()); WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager()); WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager()); +WebEntityService EMSESP::webEntityService = WebEntityService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager()); #else ESP8266React EMSESP::esp8266React(&webServer, &LittleFS); WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager()); WebCustomizationService EMSESP::webCustomizationService = WebCustomizationService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager()); WebSchedulerService EMSESP::webSchedulerService = WebSchedulerService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager()); +WebEntityService EMSESP::webEntityService = WebEntityService(&webServer, &LittleFS, EMSESP::esp8266React.getSecurityManager()); #endif WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager()); @@ -480,6 +482,7 @@ void EMSESP::publish_all(bool force) { publish_device_values(EMSdevice::DeviceType::MIXER); publish_other_values(); // switch and heat pump, ... webSchedulerService.publish(); + webEntityService.publish(); publish_sensor_values(true); // includes dallas and analog sensors system_.send_heartbeat(); } @@ -512,6 +515,7 @@ void EMSESP::publish_all_loop() { case 5: publish_other_values(); // switch and heat pump webSchedulerService.publish(true); + webEntityService.publish(true); break; case 6: publish_sensor_values(true, true); @@ -601,6 +605,7 @@ void EMSESP::publish_other_values() { // publish_device_values(EMSdevice::DeviceType::ALERT); // publish_device_values(EMSdevice::DeviceType::PUMP); // publish_device_values(EMSdevice::DeviceType::GENERIC); + webEntityService.publish(); } // publish both the dallas and analog sensor values @@ -666,6 +671,11 @@ bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const in return EMSESP::webSchedulerService.get_value_info(root, cmd); } + // own entities + if (devicetype == DeviceType::CUSTOM) { + return EMSESP::webEntityService.get_value_info(root, cmd); + } + char error[100]; snprintf(error, sizeof(error), "cannot find values for entity '%s'", cmd); root["message"] = error; @@ -866,6 +876,9 @@ bool EMSESP::process_telegram(std::shared_ptr telegram) { return false; } + // Check for custom entities reding this telegram + webEntityService.get_value(telegram); + // check for common types, like the Version(0x02) if (telegram->type_id == EMSdevice::EMS_TYPE_VERSION) { process_version(telegram); @@ -1063,6 +1076,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const name = "RF room temperature sensor"; device_type = DeviceType::THERMOSTAT; } else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT || device_id == EMSdevice::EMS_DEVICE_ID_TADO_OLD) { + // see https://github.com/emsesp/EMS-ESP32/issues/174 name = "Generic thermostat"; device_type = DeviceType::THERMOSTAT; flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE; @@ -1078,7 +1092,8 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const } else if (device_id == EMSdevice::EMS_DEVICE_ID_CASCADE) { name = "Cascade"; device_type = DeviceType::CONNECT; - } else if (device_id == EMSdevice::EMS_DEVICE_ID_EASYCOM) { + } else if (device_id == EMSdevice::EMS_DEVICE_ID_EASYCOM + || (device_id >= EMSdevice::EMS_DEVICE_ID_MODEM && device_id <= EMSdevice::EMS_DEVICE_ID_MODEM + 5)) { // see https://github.com/emsesp/EMS-ESP/issues/460#issuecomment-709553012 name = "Modem"; device_type = DeviceType::CONNECT; @@ -1372,6 +1387,7 @@ void EMSESP::scheduled_fetch_values() { return; } } + webEntityService.fetch(); no = 0; } } @@ -1453,6 +1469,7 @@ void EMSESP::start() { webCustomizationService.begin(); // load the customizations webSchedulerService.begin(); // load the scheduler events + webEntityService.begin(); // load the custom telegram reads // start telnet service if it's enabled // default idle is 10 minutes, default write timeout is 0 (automatic) diff --git a/src/emsesp.h b/src/emsesp.h index c01d8849a..3e4fa77ac 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -46,6 +46,7 @@ #include "web/WebSchedulerService.h" #include "web/WebAPIService.h" #include "web/WebLogService.h" +#include "web/WebEntityService.h" #include "emsdevicevalue.h" #include "emsdevice.h" @@ -230,6 +231,7 @@ class EMSESP { static WebLogService webLogService; static WebCustomizationService webCustomizationService; static WebSchedulerService webSchedulerService; + static WebEntityService webEntityService; private: static std::string device_tostring(const uint8_t device_id); diff --git a/src/locale_common.h b/src/locale_common.h index b069e6d7e..e45141b1a 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -98,6 +98,7 @@ MAKE_WORD(alert) MAKE_WORD(pump) MAKE_WORD(heatsource) MAKE_WORD(scheduler) +MAKE_WORD(custom) // brands MAKE_WORD_CUSTOM(bosch, "Bosch") diff --git a/src/locale_translations.h b/src/locale_translations.h index 767e02532..2546e277d 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -49,6 +49,7 @@ MAKE_WORD_TRANSLATION(pump_device, "Pump Module", "Pumpenmodul", "Pump Module", MAKE_WORD_TRANSLATION(heatsource_device, "Heatsource", "Heizquelle", "Heatsource", "Värmekälla", "Źródło ciepła", "Varmekilde", "", "Isı Kaynağı") // TODO translate MAKE_WORD_TRANSLATION(sensors_device, "Sensors", "Sensoren", "Sensoren", "Sensorer", "Czujniki", "Sensorer", "Capteurs", "Sensör Cihazı") MAKE_WORD_TRANSLATION(unknown_device, "Unknown", "Unbekannt", "Onbekend", "Okänt", "Nieznane urządzenie", "Ukjent", "Inconnu", "") // TODO translate +MAKE_WORD_TRANSLATION(custom_device, "User defined entities", "Nutzer deklarierte Entitäten", "", "", "", "", "", "") // TODO translate // commands // TODO translate @@ -64,6 +65,7 @@ MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Watch auf eingehen MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "", "", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "", "Hepsini MQTTye gönder") // TODO translate MAKE_WORD_TRANSLATION(system_info_cmd, "show system status", "Zeige System-Status", "", "", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster") // TODO translate MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplan", "", "", "aktywuj wybrany harmonogram", "", "", "") // TODO translate +MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "", "", "", "", "", "") // TODO translate // tags MAKE_WORD_TRANSLATION(tag_boiler_data_ww, "dhw", "WW", "dhw", "VV", "CWU", "dhw", "ecs", "SKS") diff --git a/src/system.cpp b/src/system.cpp index 5d2b05de0..a814c704a 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1005,6 +1005,9 @@ bool System::check_restore() { } 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); + } else if (settings_type == "entities") { + // it's a entity file, just replace it and there's no need to reboot + saveSettings(EMSESP_ENTITY_FILE, "Entities", input); } else { LOG_ERROR("Unrecognized file uploaded"); } diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp index cd5ac4894..0e31d8a96 100644 --- a/src/web/WebAPIService.cpp +++ b/src/web/WebAPIService.cpp @@ -37,6 +37,7 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getCustomizations, this, _1), AuthenticationPredicates::IS_ADMIN)); server->on(GET_SCHEDULE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSchedule, this, _1), AuthenticationPredicates::IS_ADMIN)); + server->on(GET_ENTITIES_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getEntities, this, _1), AuthenticationPredicates::IS_ADMIN)); } // HTTP GET @@ -209,4 +210,16 @@ void WebAPIService::getSchedule(AsyncWebServerRequest * request) { request->send(response); } +void WebAPIService::getEntities(AsyncWebServerRequest * request) { + auto * response = new AsyncJsonResponse(false, FS_BUFFER_SIZE); + JsonObject root = response->getRoot(); + + root["type"] = "entities"; + + System::extractSettings(EMSESP_ENTITY_FILE, "Entites", root); + + response->setLength(); + request->send(response); +} + } // namespace emsesp diff --git a/src/web/WebAPIService.h b/src/web/WebAPIService.h index c72a9ab89..2570317b5 100644 --- a/src/web/WebAPIService.h +++ b/src/web/WebAPIService.h @@ -23,6 +23,7 @@ #define GET_SETTINGS_PATH "/rest/getSettings" #define GET_CUSTOMIZATIONS_PATH "/rest/getCustomizations" #define GET_SCHEDULE_PATH "/rest/getSchedule" +#define GET_ENTITIES_PATH "/rest/getEntities" namespace emsesp { @@ -53,6 +54,7 @@ class WebAPIService { void getSettings(AsyncWebServerRequest * request); void getCustomizations(AsyncWebServerRequest * request); void getSchedule(AsyncWebServerRequest * request); + void getEntities(AsyncWebServerRequest * request); }; } // namespace emsesp diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 9aace51a5..05ecdd447 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -91,6 +91,18 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { obj["e"] = emsdevice->count_entities(); // number of entities (device values) } } + if (EMSESP::webEntityService.count_entities()) { + JsonObject obj = devices.createNestedObject(); + obj["id"] = "99"; // the last unique id as a string + obj["tn"] = "Custom"; // translated device type name + obj["t"] = EMSdevice::DeviceType::CUSTOM; // device type number + obj["b"] = 0; // brand + obj["n"] = Helpers::translated_word(FL_(custom_device)); // name + obj["d"] = 0; // deviceid + obj["p"] = 0; // productid + obj["v"] = 0; // version + obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values) + } // sensors stuff root["s_n"] = Helpers::translated_word(FL_(sensors_device)); @@ -196,6 +208,15 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & return; } } +#ifndef EMSESP_STANDALONE + if (json["id"] == 99) { + JsonObject output = response->getRoot(); + EMSESP::webEntityService.generate_value_web(output); + response->setLength(); + request->send(response); + return; + } +#endif } // invalid but send ok @@ -256,6 +277,37 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant & return; } } + if (unique_id == 99) { + // parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp + const char * cmd = dv["c"]; + int8_t id = -1; + cmd = Command::parse_command_string(cmd, id); + auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL); + JsonObject output = response->getRoot(); + JsonVariant data = dv["v"]; // the value in any format + uint8_t return_code = CommandRet::OK; + uint8_t device_type = EMSdevice::DeviceType::CUSTOM; + if (data.is()) { + char s[10]; + return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as(), 0), true, id, output); + } else if (data.is()) { + char s[10]; + return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as(), 1), true, id, output); + } else if (data.is()) { + return_code = Command::call(device_type, cmd, data.as() ? "true" : "false", true, id, output); + } + if (return_code != CommandRet::OK) { + EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code).c_str()); + } else { +#if defined(EMSESP_DEBUG) + EMSESP::logger().debug("Write command successful"); +#endif + } + response->setCode((return_code == CommandRet::OK) ? 200 : 204); + response->setLength(); + request->send(response); + return; + } } AsyncWebServerResponse * response = request->beginResponse(204); // Write command failed diff --git a/src/web/WebEntityService.cpp b/src/web/WebEntityService.cpp new file mode 100644 index 000000000..c5ff61ce4 --- /dev/null +++ b/src/web/WebEntityService.cpp @@ -0,0 +1,429 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2023 Paul Derbyshire + * + * 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 "emsesp.h" + +namespace emsesp { + +using namespace std::placeholders; // for `_1` etc + +WebEntityService::WebEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager) + : _httpEndpoint(WebEntity::read, WebEntity::update, this, server, EMSESP_ENTITY_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED) + , _fsPersistence(WebEntity::read, WebEntity::update, this, fs, EMSESP_ENTITY_FILE, FS_BUFFER_SIZE) { +} + +// load the settings when the service starts +void WebEntityService::begin() { + _fsPersistence.readFromFS(); + EMSESP::logger().info("Starting custom entity service"); +} + +// this creates the scheduler file, saving it to the FS +// and also calls when the Scheduler web page is refreshed +void WebEntity::read(WebEntity & webEntity, JsonObject & root) { + JsonArray entity = root.createNestedArray("entity"); + for (const EntityItem & entityItem : webEntity.entityItems) { + JsonObject ei = entity.createNestedObject(); + ei["device_id"] = Helpers::hextoa(entityItem.device_id, false); + ei["type_id"] = Helpers::hextoa(entityItem.type_id, false); + ei["offset"] = entityItem.offset; + ei["factor"] = entityItem.factor; + ei["name"] = entityItem.name; + ei["uom"] = entityItem.uom; + ei["val_type"] = entityItem.valuetype; + EMSESP::webEntityService.render_value(ei, entityItem, true); + } +} + +// call on initialization and also when the Schedule web page is updated +// this loads the data into the internal class +StateUpdateResult WebEntity::update(JsonObject & root, WebEntity & webEntity) { + for (EntityItem & entityItem : webEntity.entityItems) { + Command::erase_command(EMSdevice::DeviceType::CUSTOM, entityItem.name.c_str()); + } + webEntity.entityItems.clear(); + + if (root["entity"].is()) { + for (const JsonObject ei : root["entity"].as()) { + auto entityItem = EntityItem(); + entityItem.device_id = Helpers::hextoint(ei["device_id"]); + entityItem.type_id = Helpers::hextoint(ei["type_id"]); + entityItem.offset = ei["offset"]; + entityItem.factor = ei["factor"]; + entityItem.name = ei["name"].as(); + entityItem.uom = ei["uom"]; + entityItem.valuetype = ei["val_type"]; + + if (entityItem.valuetype == DeviceValueType::BOOL) { + entityItem.val = EMS_VALUE_DEFAULT_BOOL; + } else if (entityItem.valuetype == DeviceValueType::INT) { + entityItem.val = EMS_VALUE_DEFAULT_INT; + } else if (entityItem.valuetype == DeviceValueType::UINT) { + entityItem.val = EMS_VALUE_DEFAULT_UINT; + } else if (entityItem.valuetype == DeviceValueType::SHORT) { + entityItem.val = EMS_VALUE_DEFAULT_SHORT; + } else if (entityItem.valuetype == DeviceValueType::USHORT) { + entityItem.val = EMS_VALUE_DEFAULT_USHORT; + } else { // if (entityItem.valuetype == DeviceValueType::ULONG || entityItem.valuetype == DeviceValueType::TIME) { + entityItem.val = EMS_VALUE_DEFAULT_ULONG; + } + + webEntity.entityItems.push_back(entityItem); // add to list + Command::add( + EMSdevice::DeviceType::CUSTOM, + webEntity.entityItems.back().name.c_str(), + [webEntity](const char * value, const int8_t id) { return EMSESP::webEntityService.command_setvalue(value, webEntity.entityItems.back().name); }, + FL_(entity_cmd), + CommandFlag::ADMIN_ONLY); + } + } + return StateUpdateResult::CHANGED; +} + +// set value by api command +bool WebEntityService::command_setvalue(const char * value, const std::string name) { + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + for (EntityItem & entityItem : *entityItems) { + if (entityItem.name == name) { + if (entityItem.valuetype == DeviceValueType::BOOL) { + bool v; + if (!Helpers::value2bool(value, v)) { + return false; + } + EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v ? 0xFF : 0, 0); + } else { + float f; + if (!Helpers::value2float(value, f)) { + return false; + } + int v = f / entityItem.factor; + if (entityItem.valuetype == DeviceValueType::UINT || entityItem.valuetype == DeviceValueType::INT) { + EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v, 0); + } else if (entityItem.valuetype == DeviceValueType::USHORT || entityItem.valuetype == DeviceValueType::SHORT) { + uint8_t v1[2] = {(uint8_t)(v >> 8), (uint8_t)(v & 0xFF)}; + EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v1, 2, 0); + } else { + uint8_t v1[3] = {(uint8_t)(v >> 16), (uint8_t)((v & 0xFF00) >> 8), (uint8_t)(v & 0xFF)}; + EMSESP::send_write_request(entityItem.type_id, entityItem.device_id, entityItem.offset, v1, 3, 0); + } + } + publish_single(entityItem); + if (EMSESP::mqtt_.get_publish_onchange(0)) { + publish(); + } + return true; + } + } + return false; +} + +// output of a single value +void WebEntityService::render_value(JsonObject & output, EntityItem entity, const bool useVal) { + char payload[12]; + std::string name = useVal ? "value" : entity.name; + switch (entity.valuetype) { + case DeviceValueType::BOOL: + if ((uint8_t)entity.val != EMS_VALUE_BOOL_NOTSET) { + if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { + output[name] = (uint8_t)entity.val ? true : false; + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + output[name] = (uint8_t)entity.val ? 1 : 0; + } else { + output[name] = Helpers::render_boolean(payload, (uint8_t)entity.val); + } + } + break; + case DeviceValueType::INT: + if ((int8_t)entity.val != EMS_VALUE_INT_NOTSET) { + output[name] = serialized(Helpers::render_value(payload, entity.factor * (int8_t)entity.val, 2)); + } + break; + case DeviceValueType::UINT: + if ((uint8_t)entity.val != EMS_VALUE_UINT_NOTSET) { + output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint8_t)entity.val, 2)); + } + break; + case DeviceValueType::SHORT: + if ((int16_t)entity.val != EMS_VALUE_SHORT_NOTSET) { + output[name] = serialized(Helpers::render_value(payload, entity.factor * (int16_t)entity.val, 2)); + } + break; + case DeviceValueType::USHORT: + if ((uint16_t)entity.val != EMS_VALUE_USHORT_NOTSET) { + output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint16_t)entity.val, 2)); + } + break; + case DeviceValueType::ULONG: + case DeviceValueType::TIME: + if (entity.val != EMS_VALUE_ULONG_NOTSET) { + output[name] = serialized(Helpers::render_value(payload, entity.factor * entity.val, 2)); + } + break; + default: + // EMSESP::logger().warning("unknown value type"); + break; + } +} + +// process json output for info/commands and value_info +bool WebEntityService::get_value_info(JsonObject & output, const char * cmd) { + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + if (entityItems->size() == 0) { + return false; + } + if (Helpers::toLower(cmd) == "commands") { + output["info"] = "lists all values"; + output["commands"] = "lists all commands"; + for (const auto & entity : *entityItems) { + output[entity.name] = "custom entitiy"; + } + return true; + } + if (strlen(cmd) == 0 || Helpers::toLower(cmd) == "values" || Helpers::toLower(cmd) == "info") { + // list all names + for (const EntityItem & entity : *entityItems) { + render_value(output, entity); + } + return (output.size() != 0); + } + char command_s[30]; + strlcpy(command_s, cmd, sizeof(command_s)); + char * attribute_s = nullptr; + // check specific attribute to fetch instead of the complete record + char * breakp = strchr(command_s, '/'); + if (breakp) { + *breakp = '\0'; + attribute_s = breakp + 1; + } + for (const auto & entity : *entityItems) { + if (Helpers::toLower(entity.name) == Helpers::toLower(command_s)) { + output["name"] = entity.name; + output["uom"] = EMSdevice::uom_to_string(entity.uom); + output["readable"] = true; + output["writeable"] = true; + output["visible"] = true; + render_value(output, entity, true); + if (attribute_s) { + if (output.containsKey(attribute_s)) { + JsonVariant data = output[attribute_s]; + output.clear(); + output["api_data"] = data; + } else { + char error[100]; + snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s); + output.clear(); + output["message"] = error; + } + } + } + if (output.size()) { + return true; + } + } + output["message"] = "unknown command"; + return false; +} + +// publish single value +void WebEntityService::publish_single(const EntityItem & entity) { + if (!Mqtt::enabled() || !Mqtt::publish_single()) { + return; + } + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + if (Mqtt::publish_single2cmd()) { + snprintf(topic, sizeof(topic), "%s/%s", "custom", entity.name.c_str()); + } else { + snprintf(topic, sizeof(topic), "%s/%s", "custom_data", entity.name.c_str()); + } + StaticJsonDocument<256> doc; + JsonObject output = doc.to(); + render_value(output, entity, true); + Mqtt::queue_publish(topic, output["value"].as()); +} + +// publish to Mqtt +void WebEntityService::publish(const bool force) { + if (force) { + ha_registered_ = false; + } + if (!Mqtt::enabled()) { + return; + } + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + if (entityItems->size() == 0) { + return; + } + if (Mqtt::publish_single() && force) { + for (const EntityItem & entityItem : *entityItems) { + publish_single(entityItem); + } + } + + DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE); + JsonObject output = doc.to(); + for (const EntityItem & entityItem : *entityItems) { + render_value(output, entityItem); + // create HA config + if (Mqtt::ha_enabled() && !ha_registered_) { + StaticJsonDocument config; + char stat_t[50]; + snprintf(stat_t, sizeof(stat_t), "%s/custom_data", Mqtt::base().c_str()); + config["stat_t"] = stat_t; + + char val_obj[50]; + char val_cond[65]; + snprintf(val_obj, sizeof(val_obj), "value_json['%s']", entityItem.name.c_str()); + snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj); + config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; + + char uniq_s[70]; + snprintf(uniq_s, sizeof(uniq_s), "custom_%s", entityItem.name.c_str()); + + config["obj_id"] = uniq_s; + config["uniq_id"] = uniq_s; // same as object_id + config["name"] = entityItem.name.c_str(); + + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + snprintf(topic, sizeof(topic), "sensor/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); + //char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + // snprintf(command_topic, sizeof(command_topic), "%s/custom/%s", Mqtt::basename().c_str(), entityItem.name.c_str()); + // config["cmd_t"] = command_topic; + + JsonObject dev = config.createNestedObject("dev"); + JsonArray ids = dev.createNestedArray("ids"); + ids.add("ems-esp"); + + // add "availability" section + Mqtt::add_avty_to_doc(stat_t, config.as(), val_cond); + Mqtt::queue_ha(topic, config.as()); + ha_registered_ = true; + } + } + if (output.size() > 0) { + Mqtt::queue_publish("custom_data", output); + } + // EMSESP::logger().debug("publish %d custom entities", output.size()); +} + +// count only entities with valid value +uint8_t WebEntityService::count_entities() { + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + if (entityItems->size() == 0) { + return 0; + } + DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE); + JsonObject output = doc.to(); + for (const EntityItem & entity : *entityItems) { + render_value(output, entity); + } + return output.size(); +} + +// send to dashboard, msgpack don't like serialized, use number +void WebEntityService::generate_value_web(JsonObject & output) { + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + output["label"] = (std::string) "Custom Entities"; + JsonArray data = output.createNestedArray("data"); + for (const EntityItem & entity : *entityItems) { + JsonObject obj = data.createNestedObject(); // create the object, we know there is a value + obj["id"] = "00" + entity.name; + obj["u"] = entity.uom; + obj["c"] = entity.name; + switch (entity.valuetype) { + case DeviceValueType::BOOL: { + char s[12]; + obj["v"] = Helpers::render_boolean(s, (uint8_t)entity.val); + JsonArray l = obj.createNestedArray("l"); + l.add(Helpers::render_boolean(s, false, true)); + l.add(Helpers::render_boolean(s, true, true)); + break; + } + case DeviceValueType::INT: + if ((int8_t)entity.val != EMS_VALUE_INT_NOTSET) { + obj["v"] = Helpers::transformNumFloat(entity.factor * (int8_t)entity.val, 0); + } + break; + case DeviceValueType::UINT: + if ((uint8_t)entity.val != EMS_VALUE_UINT_NOTSET) { + obj["v"] = Helpers::transformNumFloat(entity.factor * (uint8_t)entity.val, 0); + } + break; + case DeviceValueType::SHORT: + if ((int16_t)entity.val != EMS_VALUE_SHORT_NOTSET) { + obj["v"] = Helpers::transformNumFloat(entity.factor * (int16_t)entity.val, 0); + } + break; + case DeviceValueType::USHORT: + if ((uint16_t)entity.val != EMS_VALUE_USHORT_NOTSET) { + obj["v"] = Helpers::transformNumFloat(entity.factor * (uint16_t)entity.val, 0); + } + break; + case DeviceValueType::ULONG: + case DeviceValueType::TIME: + if (entity.val != EMS_VALUE_ULONG_NOTSET) { + obj["v"] = Helpers::transformNumFloat(entity.factor * entity.val, 0); + } + break; + default: + break; + } + } +} + +// fetch telegram, called from emsesp::fetch +void WebEntityService::fetch() { + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + for (auto & entity : *entityItems) { + EMSESP::send_read_request(entity.type_id, entity.device_id, entity.offset); + } + // EMSESP::logger().debug("fetch custom entities"); +} + +// called on process telegram, read from telegram +bool WebEntityService::get_value(std::shared_ptr telegram) { + bool has_change = false; + EMSESP::webEntityService.read([&](WebEntity & webEntity) { entityItems = &webEntity.entityItems; }); + // read-length of BOOL, INT, UINT, SHORT, USHORT, ULONG, TIME + const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3}; + for (auto & entity : *entityItems) { + if (telegram->type_id == entity.type_id && telegram->src == entity.device_id && telegram->offset <= entity.offset + && (telegram->offset + telegram->message_length) >= (entity.offset + len[entity.valuetype])) { + uint32_t val = 0; + for (uint8_t i = 0; i < len[entity.valuetype]; i++) { + val = (val << 8) + telegram->message_data[i + entity.offset - telegram->offset]; + } + if (val != entity.val) { + entity.val = val; + if (Mqtt::publish_single()) { + publish_single(entity); + } else if (EMSESP::mqtt_.get_publish_onchange(0)) { + has_change = true; + } + } + // EMSESP::logger().debug("custom entity %s received with value %d", entity.name.c_str(), (int)entity.val); + break; + } + } + if (has_change) { + publish(); + return true; + } + return false; +} + +} // namespace emsesp diff --git a/src/web/WebEntityService.h b/src/web/WebEntityService.h new file mode 100644 index 000000000..fc58370cb --- /dev/null +++ b/src/web/WebEntityService.h @@ -0,0 +1,74 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2023 Paul Derbyshire + * + * 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 "../telegram.h" + +#ifndef WebEntityService_h +#define WebEntityService_h + +#define EMSESP_ENTITY_FILE "/config/emsespEntity.json" +#define EMSESP_ENTITY_SERVICE_PATH "/rest/entity" // GET and POST + +namespace emsesp { + +class EntityItem { + public: + uint8_t device_id; + uint16_t type_id; + uint8_t offset; + int8_t valuetype; + uint8_t uom; + std::string name; + double factor; + uint32_t val; +}; + +class WebEntity { + public: + std::list entityItems; + + static void read(WebEntity & webEntity, JsonObject & root); + static StateUpdateResult update(JsonObject & root, WebEntity & webEntity); +}; + +class WebEntityService : public StatefulService { + public: + WebEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); + + void begin(); + void publish_single(const EntityItem & entity); + void publish(const bool force = false); + bool command_setvalue(const char * value, const std::string name); + bool get_value_info(JsonObject & output, const char * cmd); + bool get_value(std::shared_ptr telegram); + void fetch(); + void render_value(JsonObject & output, EntityItem entity, const bool useVal = false); + uint8_t count_entities(); + void generate_value_web(JsonObject & output); + + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + + std::list * entityItems; // pointer to the list of schedule events + bool ha_registered_ = false; +}; + +} // namespace emsesp + +#endif \ No newline at end of file From 594e79be5db1fb7c143e48dd54ffd2eda31d113c Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 31 Mar 2023 16:52:23 +0200 Subject: [PATCH 4/5] update changelog, version dev.9 --- CHANGELOG_LATEST.md | 9 +++++++-- src/version.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 131f6213e..a45fe6e6e 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -11,16 +11,21 @@ - Detect old Tado thermostat, device-id 0x19, no entities - Some more HM200 entities [#500](https://github.com/emsesp/EMS-ESP32/issues/500) - Custom Scheduler [#701](https://github.com/emsesp/EMS-ESP32/issues/701) +- Custom Entities read from EMS bus ## Fixed - HA-discovery for analog sensor commands [#1035](https://github.com/emsesp/EMS-ESP32/issues/1035) +- Enum order of RC3x nofrost mode +- Heartbeat interval ## Changed -- Optional upgrade to platform-espressif32 6.0.0 (after 5.3.0) [#862](https://github.com/emsesp/EMS-ESP32/issues/862) -- Use byte 0 for detection RC30 active heatingcircuit [#786](https://github.com/emsesp/EMS-ESP32/issues/786) +- Optional upgrade to platform-espressif32 6.1.0 (after 5.3.0) [#862](https://github.com/emsesp/EMS-ESP32/issues/862) +- Use byte 3 for detection RC30 active heatingcircuit [#786](https://github.com/emsesp/EMS-ESP32/issues/786) - Write repeated selflowtemp if tx-queue is empty without verify [#954](https://github.com/emsesp/EMS-ESP32/issues/954) - HA discovery recreate after disconnect by device [#1067](https://github.com/emsesp/EMS-ESP32/issues/1067) - File upload: check flash size (overflow) instead of filesize - Improved HA Discovery so previous configs no longer need to be removed when starting [#1077](https://github.com/emsesp/EMS-ESP32/pull/1077) (thanks @pswid!) +- Enlarge UART-Stack to 2,5k +- Retry timeout for Mqtt-QOS1/2 10seconds diff --git a/src/version.h b/src/version.h index 0bd26f575..1335264e9 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.6.0-dev.8" +#define EMSESP_APP_VERSION "3.6.0-dev.9" From 5e2d97c0b9b096ab08c587ca545ab1425a1d11ff Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 31 Mar 2023 17:17:33 +0200 Subject: [PATCH 5/5] Typo, fix string-compare standalone --- src/web/WebAPIService.cpp | 2 +- src/web/WebSettingsService.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp index 0e31d8a96..84f94ff02 100644 --- a/src/web/WebAPIService.cpp +++ b/src/web/WebAPIService.cpp @@ -216,7 +216,7 @@ void WebAPIService::getEntities(AsyncWebServerRequest * request) { root["type"] = "entities"; - System::extractSettings(EMSESP_ENTITY_FILE, "Entites", root); + System::extractSettings(EMSESP_ENTITY_FILE, "Entities", root); response->setLength(); request->send(response); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 8d94ef5d9..4022cc4b0 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -166,7 +166,7 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) #ifndef EMSESP_STANDALONE String old_syslog_host = settings.syslog_host; settings.syslog_host = root["syslog_host"] | EMSESP_DEFAULT_SYSLOG_HOST; - if (!old_syslog_host.equals(settings.syslog_host)) { + if (old_syslog_host != settings.syslog_host) { add_flags(ChangeFlags::SYSLOG); } #endif @@ -260,7 +260,7 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) String old_locale = settings.locale; settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE; EMSESP::system_.locale(settings.locale); - if (Mqtt::ha_enabled() && !old_locale.equals(settings.locale)) { + if (Mqtt::ha_enabled() && old_locale != settings.locale) { add_flags(ChangeFlags::MQTT); }