mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
Compare commits
1081 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd2afd02be | ||
|
|
07f8f9e704 | ||
|
|
b7b09a8c93 | ||
|
|
8628bfa983 | ||
|
|
8ef8eeb9ec | ||
|
|
765ddb6702 | ||
|
|
6cab020241 | ||
|
|
cf489f7632 | ||
|
|
6943913d30 | ||
|
|
c5eaebc4b4 | ||
|
|
6905abf9f4 | ||
|
|
ef3b8a308f | ||
|
|
8a66c056d8 | ||
|
|
7967754024 | ||
|
|
800528f843 | ||
|
|
a6a60215d4 | ||
|
|
793021573a | ||
|
|
0deaafb9ce | ||
|
|
2ab50bd0a2 | ||
|
|
ecb82bd48b | ||
|
|
5592d18e1f | ||
|
|
bcfcc7690f | ||
|
|
a2fa2515b3 | ||
|
|
c8e7eb3657 | ||
|
|
24ea975575 | ||
|
|
863bc04c21 | ||
|
|
217b424320 | ||
|
|
e022c34fe7 | ||
|
|
1af103d5ee | ||
|
|
20ddbeb709 | ||
|
|
e1ad7d3c01 | ||
|
|
8f7c65c9b5 | ||
|
|
9bf7fbfb2e | ||
|
|
2739712c5b | ||
|
|
fbfaea6b56 | ||
|
|
21207f88f3 | ||
|
|
9945b8d09f | ||
|
|
ee3fafa066 | ||
|
|
eec3b3be7a | ||
|
|
77ad209ce1 | ||
|
|
8a0152ebe6 | ||
|
|
ce8d8699c3 | ||
|
|
2efb9d18c9 | ||
|
|
9af782c485 | ||
|
|
bc232fcff2 | ||
|
|
287232be5c | ||
|
|
c1058ba06c | ||
|
|
9fe6d1092a | ||
|
|
ada55ffaba | ||
|
|
c70b1c3bbd | ||
|
|
a5708e11ba | ||
|
|
8dfc84eac2 | ||
|
|
e00c30cd4f | ||
|
|
be6bb1de6a | ||
|
|
0bd57973c5 | ||
|
|
39cfa3ab79 | ||
|
|
d36fe1c0bf | ||
|
|
27aa57da3c | ||
|
|
b7bd2be0a5 | ||
|
|
9ad80fc74d | ||
|
|
7fc7c24a20 | ||
|
|
c1ae0e76c8 | ||
|
|
f1f9bacf76 | ||
|
|
4e3eb3aeaa | ||
|
|
18c5aaf598 | ||
|
|
cff60f4ed8 | ||
|
|
9fe54825f8 | ||
|
|
c5f2dba1ef | ||
|
|
b94b3e7e2e | ||
|
|
c75f7b6c7d | ||
|
|
d25ead5208 | ||
|
|
68f09f03f8 | ||
|
|
fc1e009f09 | ||
|
|
a5ef1d16d5 | ||
|
|
e80c2b0814 | ||
|
|
7ba330176a | ||
|
|
ab9caeba9c | ||
|
|
7a5eeaa88a | ||
|
|
bb3550810d | ||
|
|
5bdf7978bf | ||
|
|
f77fb12c80 | ||
|
|
9fc109eec1 | ||
|
|
f1342e4d62 | ||
|
|
854f764b3c | ||
|
|
463c68d08c | ||
|
|
2ddd2401eb | ||
|
|
ff045b1a01 | ||
|
|
7c73e70986 | ||
|
|
8699bd4eb0 | ||
|
|
626c32763f | ||
|
|
56c958a141 | ||
|
|
d09abc1b49 | ||
|
|
8c4fc495a3 | ||
|
|
fd1d4b97a0 | ||
|
|
d8b77fc056 | ||
|
|
82579869a4 | ||
|
|
12690eeaf4 | ||
|
|
a359618cca | ||
|
|
20165a528d | ||
|
|
3a23dae178 | ||
|
|
e50d4fafb5 | ||
|
|
673b4c2881 | ||
|
|
b676c4d164 | ||
|
|
40716f9c55 | ||
|
|
df0210bfac | ||
|
|
41ac8120d0 | ||
|
|
6a66c7def7 | ||
|
|
3b0b6d75a7 | ||
|
|
292ed242c4 | ||
|
|
bb670e97ff | ||
|
|
768bdcaaaa | ||
|
|
1db4a33a1d | ||
|
|
61d11ce440 | ||
|
|
08918a7349 | ||
|
|
87542fb9df | ||
|
|
fb09386c22 | ||
|
|
d42ae52aff | ||
|
|
271d1fda92 | ||
|
|
df982e3ea9 | ||
|
|
222aaca218 | ||
|
|
8a56c599e6 | ||
|
|
003d3740af | ||
|
|
74342ba654 | ||
|
|
392015f3af | ||
|
|
c769fd6d2c | ||
|
|
0f06bfa91c | ||
|
|
dffc4a7c02 | ||
|
|
34201025c3 | ||
|
|
189ea6b23d | ||
|
|
24f2d86059 | ||
|
|
1a08ab6a2b | ||
|
|
5e5e6ff053 | ||
|
|
08204a94d8 | ||
|
|
0eb3df704e | ||
|
|
2eb77b5f97 | ||
|
|
33b6ece55b | ||
|
|
0010f71a3c | ||
|
|
38a546d6f7 | ||
|
|
4346de27b6 | ||
|
|
d797c3371b | ||
|
|
5d3f8e5b69 | ||
|
|
8ebc552cac | ||
|
|
944d86b644 | ||
|
|
8bd2a39d4e | ||
|
|
ed9cad6e39 | ||
|
|
e31330e931 | ||
|
|
49d749e89f | ||
|
|
d3fadd7081 | ||
|
|
31ff0f5aba | ||
|
|
b24a63b992 | ||
|
|
f5ec9e9602 | ||
|
|
b6accb8d02 | ||
|
|
a35486ec24 | ||
|
|
fdaa9a6188 | ||
|
|
daf08e7bd9 | ||
|
|
994e1fc26b | ||
|
|
34b7dd61cf | ||
|
|
ce3c3e0b3e | ||
|
|
92a80c3aaf | ||
|
|
df21c15972 | ||
|
|
b683d1dd21 | ||
|
|
a7d0259b30 | ||
|
|
16779064f4 | ||
|
|
732ad4bc6a | ||
|
|
f40a6f20c6 | ||
|
|
4bf22dd6a5 | ||
|
|
62ae5332de | ||
|
|
12e65279ef | ||
|
|
295b90f49c | ||
|
|
644907e58b | ||
|
|
a8a875f9d5 | ||
|
|
6cd9dfc685 | ||
|
|
80a3007f8b | ||
|
|
ed5f0bc6d5 | ||
|
|
df1109ea39 | ||
|
|
1f7c968d0d | ||
|
|
65cf8005a4 | ||
|
|
7c97aaf735 | ||
|
|
23cfdd9b34 | ||
|
|
b454e87405 | ||
|
|
3d715c45e0 | ||
|
|
fea63b0d52 | ||
|
|
ce33fa6535 | ||
|
|
57296e55f2 | ||
|
|
12f0120afd | ||
|
|
303e86a5eb | ||
|
|
52479c408f | ||
|
|
fc8eea91eb | ||
|
|
fe5a6fb568 | ||
|
|
55672cc9de | ||
|
|
6d6291e659 | ||
|
|
c2be9b210e | ||
|
|
257b40c2e4 | ||
|
|
e6b61b7a51 | ||
|
|
f167be37a1 | ||
|
|
4ac2d1a9a7 | ||
|
|
8c602cd058 | ||
|
|
b8f6664176 | ||
|
|
1024dbb61f | ||
|
|
464341c2cb | ||
|
|
f765d7c31b | ||
|
|
72b64a0c30 | ||
|
|
2b88fec2ee | ||
|
|
119b2b9514 | ||
|
|
4f406e8d33 | ||
|
|
0d80f58ea6 | ||
|
|
6c7a3ad68c | ||
|
|
52a8b20c54 | ||
|
|
5213382246 | ||
|
|
0b452ddd39 | ||
|
|
253adfeb45 | ||
|
|
355c7cbd92 | ||
|
|
99d7ff0dc7 | ||
|
|
6564e444ab | ||
|
|
51b0a0ae5b | ||
|
|
738d9b1d94 | ||
|
|
4319d648aa | ||
|
|
2595b906a5 | ||
|
|
c98e1a629b | ||
|
|
ae7f0445a3 | ||
|
|
8406657906 | ||
|
|
9135635af2 | ||
|
|
25098409df | ||
|
|
8176120bf9 | ||
|
|
5cfb7b4548 | ||
|
|
3f17d74bc6 | ||
|
|
1694a0b41d | ||
|
|
ec8a182aa3 | ||
|
|
22b70ac378 | ||
|
|
40a685aeb2 | ||
|
|
a580998f25 | ||
|
|
faa888ff36 | ||
|
|
afc34fc387 | ||
|
|
45335be4ed | ||
|
|
b834c8fd89 | ||
|
|
24162b7350 | ||
|
|
3bb7e3514f | ||
|
|
58b75ee203 | ||
|
|
d32178480d | ||
|
|
38e08be752 | ||
|
|
9573c4ed94 | ||
|
|
56e5e87238 | ||
|
|
ef47ee62a3 | ||
|
|
a9a2380287 | ||
|
|
5bd9ec963f | ||
|
|
427e8cf11c | ||
|
|
de9c224a23 | ||
|
|
5532d20657 | ||
|
|
b7ce69ee2d | ||
|
|
00b3525503 | ||
|
|
1065c9eec9 | ||
|
|
8d3dd9d8e9 | ||
|
|
0f799d5922 | ||
|
|
3a8bed6976 | ||
|
|
aadf4b7a53 | ||
|
|
ed7ba17bc7 | ||
|
|
526c36728f | ||
|
|
c7a35ebc58 | ||
|
|
5735ffd222 | ||
|
|
d11508282f | ||
|
|
30e11ad593 | ||
|
|
040954bb70 | ||
|
|
eec0051997 | ||
|
|
fab74a9061 | ||
|
|
8e9edcb673 | ||
|
|
2bd66bf4b6 | ||
|
|
ce6e89338f | ||
|
|
9e423d9769 | ||
|
|
52bb6b8218 | ||
|
|
5748bd4074 | ||
|
|
6155645436 | ||
|
|
85a839e86b | ||
|
|
0760e6e021 | ||
|
|
fbd3ebbd4e | ||
|
|
24b8e004ec | ||
|
|
542246c142 | ||
|
|
31bea94d9c | ||
|
|
5669deeb80 | ||
|
|
34cafe0d4d | ||
|
|
e319f5e270 | ||
|
|
133decf453 | ||
|
|
541615d405 | ||
|
|
1042298541 | ||
|
|
6aca61deee | ||
|
|
9266454f82 | ||
|
|
21de630f8e | ||
|
|
8a0e037c60 | ||
|
|
326e7bcc2a | ||
|
|
cc8839ab31 | ||
|
|
fcffa3df5c | ||
|
|
27d0ba0526 | ||
|
|
18d329f3ee | ||
|
|
9e064eb564 | ||
|
|
2764185132 | ||
|
|
79d7142e5f | ||
|
|
2a3838771a | ||
|
|
8d712c47f0 | ||
|
|
a3ccc83cf3 | ||
|
|
fe30b8de8d | ||
|
|
d8671dd114 | ||
|
|
603036a5e9 | ||
|
|
9eb617bcb0 | ||
|
|
82e1b069eb | ||
|
|
89da6d5851 | ||
|
|
1491f283a8 | ||
|
|
a8c3b21ee6 | ||
|
|
1b27e1fd09 | ||
|
|
d99222450c | ||
|
|
ef075787dc | ||
|
|
ec411a7dff | ||
|
|
fd4f649db3 | ||
|
|
0c93f1daa5 | ||
|
|
7da2806ab4 | ||
|
|
f88685833d | ||
|
|
c0e77698aa | ||
|
|
9fd7b2553c | ||
|
|
bb5ca8a804 | ||
|
|
cd8921e78e | ||
|
|
9260db330e | ||
|
|
3b32dcb407 | ||
|
|
549a0302b7 | ||
|
|
4d1a428acf | ||
|
|
cc83dab97b | ||
|
|
65ff765219 | ||
|
|
d5cb5c1c51 | ||
|
|
4974208a65 | ||
|
|
e88ede2d8b | ||
|
|
2b6fd41d5a | ||
|
|
e26208a5e9 | ||
|
|
12a545ddbf | ||
|
|
4ad5c7299e | ||
|
|
c04371dfae | ||
|
|
d810494211 | ||
|
|
18dd207d3c | ||
|
|
a34c8661bd | ||
|
|
f9516860e3 | ||
|
|
ded7b547e1 | ||
|
|
77607263a9 | ||
|
|
c55e05e7b2 | ||
|
|
d529cbf269 | ||
|
|
c578154b5e | ||
|
|
6c398109f4 | ||
|
|
bbfdb0ff0e | ||
|
|
48de155201 | ||
|
|
a2cfe00113 | ||
|
|
e0c8557d5c | ||
|
|
74691ce34a | ||
|
|
ef6ac3848f | ||
|
|
5c490834cf | ||
|
|
d6aa1fb48b | ||
|
|
2190db77ad | ||
|
|
7b4f76d51d | ||
|
|
16010b2223 | ||
|
|
8c2aba8eb1 | ||
|
|
c834c5e43e | ||
|
|
94f268a62d | ||
|
|
1f81ccb686 | ||
|
|
356180dbf9 | ||
|
|
ea2d5b77c0 | ||
|
|
81b0b77e2b | ||
|
|
af1209cb04 | ||
|
|
b6ec8e14ec | ||
|
|
63cf4bdc21 | ||
|
|
1d025d5b97 | ||
|
|
cf8c5430d1 | ||
|
|
1dde495f61 | ||
|
|
c3650817ef | ||
|
|
3f10523e66 | ||
|
|
8ddc167f93 | ||
|
|
54d2f38841 | ||
|
|
ad9e463923 | ||
|
|
5f2859fae2 | ||
|
|
2b03d01a15 | ||
|
|
2366f6ba50 | ||
|
|
10d6728c82 | ||
|
|
778cdaabb6 | ||
|
|
efa4f80b99 | ||
|
|
f25ab5f293 | ||
|
|
ae15c7ccd0 | ||
|
|
025f43953a | ||
|
|
bf95205af6 | ||
|
|
cb11305416 | ||
|
|
5e0c6a527a | ||
|
|
8540e71145 | ||
|
|
cb2746b741 | ||
|
|
209644d500 | ||
|
|
273dc4b83c | ||
|
|
75574f663b | ||
|
|
462870fe6b | ||
|
|
f365fe5317 | ||
|
|
19eb755157 | ||
|
|
26e4badc1b | ||
|
|
fb00f4eef9 | ||
|
|
2ef85bb9fa | ||
|
|
2dfba3f7d0 | ||
|
|
5259d55f23 | ||
|
|
af237c4fc0 | ||
|
|
13a915e1f4 | ||
|
|
df33a24951 | ||
|
|
e62fc14b6d | ||
|
|
591b8afcb0 | ||
|
|
35ee8c33b3 | ||
|
|
9ca47627d2 | ||
|
|
4c27cb831e | ||
|
|
a3b6656be7 | ||
|
|
b0076cd5da | ||
|
|
b6dbf93de2 | ||
|
|
e8217b68a5 | ||
|
|
ebfe487a3a | ||
|
|
ce34567939 | ||
|
|
3f42c4d56b | ||
|
|
55ce551868 | ||
|
|
d16e77bba3 | ||
|
|
c9efd095e7 | ||
|
|
8384344c5a | ||
|
|
cb5f707b2d | ||
|
|
e525552e10 | ||
|
|
78bd0a1b76 | ||
|
|
1316fe9509 | ||
|
|
c45fd23227 | ||
|
|
d6856e8a23 | ||
|
|
5fcad37fb9 | ||
|
|
ab58a3dfd3 | ||
|
|
a81695e973 | ||
|
|
8d1a36c669 | ||
|
|
0fce450418 | ||
|
|
3a92d69c77 | ||
|
|
fa1a372468 | ||
|
|
62b341a614 | ||
|
|
0058632d71 | ||
|
|
339408e12a | ||
|
|
8bffa6b304 | ||
|
|
7c80364bcf | ||
|
|
ac950e0e92 | ||
|
|
77700c4873 | ||
|
|
d035a29f24 | ||
|
|
4c51b90663 | ||
|
|
8d33a89e39 | ||
|
|
41260a4370 | ||
|
|
7d15a8010d | ||
|
|
606a7e6eec | ||
|
|
83e400fbe9 | ||
|
|
d3ae73e6b2 | ||
|
|
b4b2531e33 | ||
|
|
225e482814 | ||
|
|
ddd1f5de5b | ||
|
|
446601c6e0 | ||
|
|
9f3e2dbcd3 | ||
|
|
3163a142a9 | ||
|
|
dcb0d5087f | ||
|
|
e2544947f7 | ||
|
|
19743da558 | ||
|
|
08c5fd8f64 | ||
|
|
a28cdaa930 | ||
|
|
3f31962a9a | ||
|
|
651b1b1c50 | ||
|
|
ca2ca972b9 | ||
|
|
215c4e49ca | ||
|
|
d1dbce84c7 | ||
|
|
fb4a0b0ae8 | ||
|
|
854a39fe6b | ||
|
|
a01ee4a48d | ||
|
|
8ed867314d | ||
|
|
abf4eeb39a | ||
|
|
40a85634ef | ||
|
|
a5c41a1cd8 | ||
|
|
c6668e1d6a | ||
|
|
5384abc780 | ||
|
|
444d5fb7c3 | ||
|
|
3b76a020c7 | ||
|
|
804187afb9 | ||
|
|
ef2ed0f4d1 | ||
|
|
68084fc9b5 | ||
|
|
a684a46404 | ||
|
|
1556bf02ba | ||
|
|
b29c36d01d | ||
|
|
68cb94547e | ||
|
|
a0e1894262 | ||
|
|
ee584375c5 | ||
|
|
ac288b794f | ||
|
|
a1f296b2ae | ||
|
|
9b1e399730 | ||
|
|
dd6b435417 | ||
|
|
3d5c08118c | ||
|
|
29a3e79804 | ||
|
|
d78d4aed9d | ||
|
|
9f34531956 | ||
|
|
d1f3ead8b9 | ||
|
|
a33f17932f | ||
|
|
eb05b83009 | ||
|
|
367c022e6c | ||
|
|
b9af4325c9 | ||
|
|
1ae2a624f7 | ||
|
|
d4c9a3c846 | ||
|
|
0b481a44a1 | ||
|
|
513d0e982e | ||
|
|
2629471a56 | ||
|
|
c1ce4f1b73 | ||
|
|
faa21abe54 | ||
|
|
72f4d00cb3 | ||
|
|
c9f5b0a2c1 | ||
|
|
8453422c9c | ||
|
|
ed060a400d | ||
|
|
6c3e5d976c | ||
|
|
443050ae28 | ||
|
|
d81b833951 | ||
|
|
510602e117 | ||
|
|
4008883627 | ||
|
|
4081a55207 | ||
|
|
c9ca395e6d | ||
|
|
c3ac215493 | ||
|
|
10cabd032b | ||
|
|
7b9a04ede1 | ||
|
|
1845d5060a | ||
|
|
9375fb4d2d | ||
|
|
f9b8ac6f30 | ||
|
|
ad577eaa2a | ||
|
|
42ba93bdc1 | ||
|
|
fd5f5d49b7 | ||
|
|
80f4e63850 | ||
|
|
7efa8ffbe0 | ||
|
|
85016d6582 | ||
|
|
06bf2f3427 | ||
|
|
c38832ef06 | ||
|
|
c1fa5c42c4 | ||
|
|
2faa78bc32 | ||
|
|
b5633cd579 | ||
|
|
4275d144ca | ||
|
|
7f794f35a6 | ||
|
|
8d778f902f | ||
|
|
f83f22a6fb | ||
|
|
03b6ebd861 | ||
|
|
0d4607a922 | ||
|
|
067100d375 | ||
|
|
306baee94d | ||
|
|
cb1989b2ea | ||
|
|
7ce99cb1fb | ||
|
|
3a36663d94 | ||
|
|
9118cd7c5b | ||
|
|
8b0cf599f4 | ||
|
|
ba21293c42 | ||
|
|
8574b44d4e | ||
|
|
76901d97d2 | ||
|
|
1cbfc91912 | ||
|
|
7d6bb6b9c8 | ||
|
|
c81f579464 | ||
|
|
2a6fedc6b3 | ||
|
|
e3a7e9fe33 | ||
|
|
8898ec9419 | ||
|
|
548fdd823b | ||
|
|
b60127c3ba | ||
|
|
095255b9b7 | ||
|
|
2b486ffa36 | ||
|
|
c3f9d9ddd6 | ||
|
|
740f3b4ef7 | ||
|
|
932a496f47 | ||
|
|
d36246d4d1 | ||
|
|
19094d47aa | ||
|
|
24cca67625 | ||
|
|
41443d4efe | ||
|
|
6e08356ff7 | ||
|
|
751410ca58 | ||
|
|
60beeddb66 | ||
|
|
c61c34f10e | ||
|
|
96a04da1ff | ||
|
|
bd8472b34e | ||
|
|
09228e4637 | ||
|
|
40a79c51ce | ||
|
|
01a15a5c85 | ||
|
|
1e15f65b0d | ||
|
|
0818728c25 | ||
|
|
2edfe0f42c | ||
|
|
a2eb8dfe83 | ||
|
|
4c60545057 | ||
|
|
d06b3285bd | ||
|
|
4dcfe8e0f6 | ||
|
|
42e679d5ba | ||
|
|
4db1c7dfca | ||
|
|
64fb84dd54 | ||
|
|
5ad03facce | ||
|
|
ad3bf294d8 | ||
|
|
6dba452aea | ||
|
|
cff5b8c949 | ||
|
|
aed45968db | ||
|
|
2de855e044 | ||
|
|
dfd9fe4d01 | ||
|
|
049f956131 | ||
|
|
b503e2bb90 | ||
|
|
b300181d33 | ||
|
|
905b52e39d | ||
|
|
8fcfb3d8f7 | ||
|
|
a17a9b71a2 | ||
|
|
64d46fe8f7 | ||
|
|
7962af0872 | ||
|
|
873b75240c | ||
|
|
9e405c5a5a | ||
|
|
e20434da88 | ||
|
|
9c8677acb9 | ||
|
|
1c3bc98bbb | ||
|
|
02616696dc | ||
|
|
00d66c1c4e | ||
|
|
8cfc540670 | ||
|
|
a4062f5d84 | ||
|
|
edee463ade | ||
|
|
64471e4c0e | ||
|
|
28a7ceb6aa | ||
|
|
0a10e78bfd | ||
|
|
e4a899912c | ||
|
|
cc9819b56b | ||
|
|
29f86c9ab9 | ||
|
|
722ca34a18 | ||
|
|
50777bd681 | ||
|
|
2f5558c311 | ||
|
|
21c3fe5d8e | ||
|
|
acb453bd4b | ||
|
|
bc39b738e2 | ||
|
|
1ada18ec9a | ||
|
|
6b9dadc0d9 | ||
|
|
cf89a06437 | ||
|
|
4a1ea99ee7 | ||
|
|
3dbf8a0fd1 | ||
|
|
9c6b9a5359 | ||
|
|
0d07a9e50c | ||
|
|
7b5a37a85d | ||
|
|
0b5a7b9f2a | ||
|
|
0f99415bbf | ||
|
|
c9775c1edd | ||
|
|
1f1b571e91 | ||
|
|
21e28e970c | ||
|
|
f9e1940c7b | ||
|
|
72c0625823 | ||
|
|
4f1ef297c7 | ||
|
|
3b30083e7c | ||
|
|
50590f4924 | ||
|
|
fae876d7d2 | ||
|
|
c1dabddf21 | ||
|
|
6926f6fd0b | ||
|
|
e30c476e5c | ||
|
|
509122bf4b | ||
|
|
84fab951ba | ||
|
|
a8ea6ef4a8 | ||
|
|
196e98b3bd | ||
|
|
a0f1f51cca | ||
|
|
d717b72a9e | ||
|
|
eccece7207 | ||
|
|
499ff0d31e | ||
|
|
ae0599d13d | ||
|
|
1a9cf4ebdc | ||
|
|
386082b747 | ||
|
|
fc02721815 | ||
|
|
529970fb19 | ||
|
|
752ce333ec | ||
|
|
f34be2a884 | ||
|
|
bed1650350 | ||
|
|
1f8a477939 | ||
|
|
8e844550bf | ||
|
|
dfd2a017c2 | ||
|
|
c40a11504c | ||
|
|
fd81299da1 | ||
|
|
9993a7c739 | ||
|
|
ea38011085 | ||
|
|
2079b7e602 | ||
|
|
101159b9f6 | ||
|
|
1442568790 | ||
|
|
6699d9ad80 | ||
|
|
1b27fae844 | ||
|
|
253eb72dbf | ||
|
|
4b6b89f1a0 | ||
|
|
fe772f85bf | ||
|
|
a2422e1f6a | ||
|
|
8ba40003e4 | ||
|
|
ac0fb52ce9 | ||
|
|
031c97a162 | ||
|
|
f7d3939c72 | ||
|
|
20f32db8bc | ||
|
|
0e55caf721 | ||
|
|
4d5f8cc96a | ||
|
|
434ef2b333 | ||
|
|
e0ab208c52 | ||
|
|
5b1f3d266e | ||
|
|
4c83f5fe60 | ||
|
|
981d62dc2c | ||
|
|
ffcf0bf2d7 | ||
|
|
7997544fb8 | ||
|
|
7e1f16c865 | ||
|
|
765e6bcd69 | ||
|
|
81b654cc41 | ||
|
|
3fc36b5e50 | ||
|
|
52077cbd07 | ||
|
|
a45f1badba | ||
|
|
f38f4bc85a | ||
|
|
8c03592157 | ||
|
|
e7254bc7f4 | ||
|
|
5d0242b47c | ||
|
|
5997dd1491 | ||
|
|
31a5216ae8 | ||
|
|
5c0c0675a2 | ||
|
|
ba9f16da00 | ||
|
|
110ee59cd1 | ||
|
|
555bf8cb2f | ||
|
|
5f1dddf7e4 | ||
|
|
2f658a9a14 | ||
|
|
c3f487eced | ||
|
|
a8a12dd1f8 | ||
|
|
7f7e3c47ec | ||
|
|
eafeb5c5d2 | ||
|
|
caca8bf802 | ||
|
|
338091578b | ||
|
|
bf5b40ccf4 | ||
|
|
58cbfbc0df | ||
|
|
06f5e1226f | ||
|
|
af57af46b0 | ||
|
|
3f91377751 | ||
|
|
c4c9ed739f | ||
|
|
2a8d3b8cd6 | ||
|
|
af1292caa0 | ||
|
|
44afa1a30f | ||
|
|
fa184a8f94 | ||
|
|
387c2eebcd | ||
|
|
cd6a0da9f0 | ||
|
|
188bfa4525 | ||
|
|
037a9848bc | ||
|
|
b6543169de | ||
|
|
14b3b058fe | ||
|
|
fa4763309d | ||
|
|
adcc59642c | ||
|
|
d18fd4948c | ||
|
|
c10ecb097e | ||
|
|
4e4258f9dc | ||
|
|
ab6cf78822 | ||
|
|
d105c18bf7 | ||
|
|
6bbf4e4778 | ||
|
|
3101f5e6ae | ||
|
|
207953e8d1 | ||
|
|
a449ebd0ea | ||
|
|
2afe50fc9e | ||
|
|
cd564f0c54 | ||
|
|
8eba09fea6 | ||
|
|
6c17d61baf | ||
|
|
6df1f2850f | ||
|
|
288d9b70b7 | ||
|
|
8307b0920c | ||
|
|
1097b519ae | ||
|
|
e7b7002883 | ||
|
|
c934b9e8d9 | ||
|
|
0838d06ec4 | ||
|
|
41666458d9 | ||
|
|
b02207a0d7 | ||
|
|
faafd51e40 | ||
|
|
94cf81c164 | ||
|
|
1cd97cf1ee | ||
|
|
6f097e4613 | ||
|
|
90af88f36d | ||
|
|
862cc2545b | ||
|
|
74c6e54dc5 | ||
|
|
33ac89e202 | ||
|
|
89d591500c | ||
|
|
9bf56b2e6d | ||
|
|
7c3dac3da7 | ||
|
|
6853651c8b | ||
|
|
16a9bc4fae | ||
|
|
70d4bcf097 | ||
|
|
1991ca4128 | ||
|
|
879df338e3 | ||
|
|
29c1169b33 | ||
|
|
362b6a1394 | ||
|
|
f5f5901ad9 | ||
|
|
757bf58992 | ||
|
|
af8e77029e | ||
|
|
94519179df | ||
|
|
527dd870a2 | ||
|
|
b9e57414ce | ||
|
|
e3a644182e | ||
|
|
caadb506d8 | ||
|
|
597f0b147d | ||
|
|
0b9a2483b2 | ||
|
|
6a221e84cc | ||
|
|
7ea7a4b25a | ||
|
|
c494627867 | ||
|
|
5032c37f63 | ||
|
|
f5cd92d567 | ||
|
|
240b7dad32 | ||
|
|
2bac805ebf | ||
|
|
b1a3d6ea20 | ||
|
|
77cfad9ff0 | ||
|
|
2dc1bd71ee | ||
|
|
fcdc4314e3 | ||
|
|
900112a967 | ||
|
|
114a8af467 | ||
|
|
e2c2a12a2b | ||
|
|
222f853616 | ||
|
|
450f5a465c | ||
|
|
ba106eecc0 | ||
|
|
374bd7c5c2 | ||
|
|
31b2005320 | ||
|
|
8ae5570c70 | ||
|
|
96fe9aeb31 | ||
|
|
4a7d69c797 | ||
|
|
7dca77450c | ||
|
|
9bb157bbe6 | ||
|
|
6c7787b2ae | ||
|
|
ec5b5ef79d | ||
|
|
6abd56c7e2 | ||
|
|
1fdeaf8b24 | ||
|
|
ad51870d2c | ||
|
|
8929e15e00 | ||
|
|
3f31e636ec | ||
|
|
5e7e1c30ca | ||
|
|
5cf0d8d204 | ||
|
|
dbbd475934 | ||
|
|
bf9877b528 | ||
|
|
5e6b0f64bd | ||
|
|
509d213536 | ||
|
|
4c789a656b | ||
|
|
2f6edfd505 | ||
|
|
9c2d861b93 | ||
|
|
2c0d4fdcef | ||
|
|
be93627ec0 | ||
|
|
c6c7754735 | ||
|
|
07bdf28350 | ||
|
|
fd49f0372a | ||
|
|
36ca7e09ca | ||
|
|
7a36c5e8cb | ||
|
|
15b97515bb | ||
|
|
4048f58856 | ||
|
|
b0ea3184a4 | ||
|
|
6ab2cc60e7 | ||
|
|
237d631e2c | ||
|
|
0ed46679e2 | ||
|
|
1fded64f2e | ||
|
|
161f782904 | ||
|
|
3fe9296139 | ||
|
|
9698e787b2 | ||
|
|
eb274a94c3 | ||
|
|
18be921c1b | ||
|
|
fddfa47b51 | ||
|
|
c533e91643 | ||
|
|
de2792ffdd | ||
|
|
97de23f521 | ||
|
|
c212520f4f | ||
|
|
dc739b97ab | ||
|
|
2583da8714 | ||
|
|
ddfc9f9dd0 | ||
|
|
7d855326d0 | ||
|
|
a1bb49359f | ||
|
|
f9a176e09c | ||
|
|
24d5ac7656 | ||
|
|
558fa20283 | ||
|
|
c42ead995e | ||
|
|
8584901229 | ||
|
|
a17f8db035 | ||
|
|
6783d5b3e8 | ||
|
|
9223a00270 | ||
|
|
c150c578a6 | ||
|
|
5be1482c20 | ||
|
|
20e301594c | ||
|
|
f90f4279d7 | ||
|
|
9962f16d62 | ||
|
|
cb10663735 | ||
|
|
2ab247131f | ||
|
|
c0a3d03a09 | ||
|
|
baa180cc79 | ||
|
|
dbc59b7c8c | ||
|
|
c4d1058133 | ||
|
|
3a8495ca54 | ||
|
|
dad62613f6 | ||
|
|
9641adce1c | ||
|
|
67693364cc | ||
|
|
d37a5c5713 | ||
|
|
a881431010 | ||
|
|
2866862730 | ||
|
|
c234e70a87 | ||
|
|
61296896bd | ||
|
|
2acb45db47 | ||
|
|
abe0d793d6 | ||
|
|
654403ca3d | ||
|
|
b111e4762a | ||
|
|
8bd796b772 | ||
|
|
84b6611ffd | ||
|
|
58b3f309bd | ||
|
|
0bd4330881 | ||
|
|
68feb0fa30 | ||
|
|
b4e266f128 | ||
|
|
855794dbe8 | ||
|
|
2a38981c67 | ||
|
|
63b4a62fac | ||
|
|
710fd1bc79 | ||
|
|
f5ab7510b4 | ||
|
|
ecd37223e8 | ||
|
|
99992db9ac | ||
|
|
3ecea985ad | ||
|
|
ae1b6fc67b | ||
|
|
020bb628d6 | ||
|
|
22a4338e7a | ||
|
|
1f089ec6f9 | ||
|
|
0f78d4f34d | ||
|
|
8395983106 | ||
|
|
87ce1a6d9b | ||
|
|
ac4eba5b72 | ||
|
|
5e53689a81 | ||
|
|
895eddd8d2 | ||
|
|
a8c7b2bca4 | ||
|
|
6f46382806 | ||
|
|
b8af3e235f | ||
|
|
531c2e7b5d | ||
|
|
f76e6b56b1 | ||
|
|
c388b31b22 | ||
|
|
cbb6fa9fec | ||
|
|
a3300e94a7 | ||
|
|
3c8a00be09 | ||
|
|
36ae55e543 | ||
|
|
8b5d893977 | ||
|
|
bd851f9005 | ||
|
|
208be85304 | ||
|
|
9dd613394c | ||
|
|
62eeca944b | ||
|
|
17d7487423 | ||
|
|
ae589c745b | ||
|
|
4b41180785 | ||
|
|
7748f67b9a | ||
|
|
20d8b6400f | ||
|
|
d3b086a675 | ||
|
|
e1ee83b907 | ||
|
|
763a2eaab1 | ||
|
|
5d78f1c814 | ||
|
|
3f99806ddd | ||
|
|
bc0a90ee41 | ||
|
|
3900b8fc94 | ||
|
|
f9a53cf320 | ||
|
|
99467558b4 | ||
|
|
2e25e46f6f | ||
|
|
3a1b7cae67 | ||
|
|
5bc3bd23e2 | ||
|
|
a04f4d784b | ||
|
|
9c423dc886 | ||
|
|
1b0f840d18 | ||
|
|
21eaf70181 | ||
|
|
14f2cd4bee | ||
|
|
917e268ac9 | ||
|
|
41228e894a | ||
|
|
365c95991b | ||
|
|
ba4ebe221c | ||
|
|
3ab5946e38 | ||
|
|
f427288c06 | ||
|
|
398cbadb64 | ||
|
|
38a1c9e9d7 | ||
|
|
5abfdf1177 | ||
|
|
385d2377db | ||
|
|
6655035561 | ||
|
|
755408e6aa | ||
|
|
df70ed0062 | ||
|
|
b893290b62 | ||
|
|
96ff5ed123 | ||
|
|
dcdd8d9e44 | ||
|
|
5c484d58dc | ||
|
|
96bf1a32ee | ||
|
|
ad81f84c02 | ||
|
|
529b46d776 | ||
|
|
bbc5bc8585 | ||
|
|
9c33b5cb8b | ||
|
|
ba7ceca798 | ||
|
|
4824152ae5 | ||
|
|
af935d8124 | ||
|
|
951e706fee | ||
|
|
9f1002df9a | ||
|
|
6ab2135cea | ||
|
|
e6bcdede73 | ||
|
|
8b136ddefe | ||
|
|
ca9ac86fde | ||
|
|
42a4c792ad | ||
|
|
a6b0c74f5f | ||
|
|
09e2945c15 | ||
|
|
a3f05cb08b | ||
|
|
0ab573225d | ||
|
|
4c8fd45908 | ||
|
|
8bb703fafe | ||
|
|
9cdeb7c07a | ||
|
|
8d4b43e9f6 | ||
|
|
d8c298f6fe | ||
|
|
8a16566f53 | ||
|
|
9d3456cb3a | ||
|
|
7310db6426 | ||
|
|
ac08bb6037 | ||
|
|
776f72650f | ||
|
|
0eb96e764c | ||
|
|
ec939dfc2e | ||
|
|
809b6be79c | ||
|
|
34f87a0a21 | ||
|
|
bc4418755e | ||
|
|
d24742facd | ||
|
|
9c16e2008e | ||
|
|
6a7a9636ac | ||
|
|
5e76bfa210 | ||
|
|
4da45a7240 | ||
|
|
3c84a1ced1 | ||
|
|
677f6c5a6e | ||
|
|
3ce67b8e6e | ||
|
|
aad9c12a7e | ||
|
|
877d60f46f | ||
|
|
bf02b0ad1c | ||
|
|
2f5b7cd0aa | ||
|
|
4bec32ea56 | ||
|
|
33ea1c6863 | ||
|
|
09ff892b91 | ||
|
|
f462afb547 | ||
|
|
83211e0ef8 | ||
|
|
b7b3cb177f | ||
|
|
10c8c2b4a7 | ||
|
|
c19345c345 | ||
|
|
04fd04b2ab | ||
|
|
6e3c2b2ec9 | ||
|
|
98e29516b0 | ||
|
|
6db5058e3d | ||
|
|
b3ada4a01f | ||
|
|
f38e0abf73 | ||
|
|
6376ed2361 | ||
|
|
04e43d5d41 | ||
|
|
0ba5d8e2bd | ||
|
|
95b8e79624 | ||
|
|
e9c3f8c6da | ||
|
|
27aa72eda1 | ||
|
|
01f6024776 | ||
|
|
aa5730c683 | ||
|
|
fcc2a48192 | ||
|
|
1c4da53e75 | ||
|
|
09a15727c7 | ||
|
|
f1034f4230 | ||
|
|
06e9b8d303 | ||
|
|
b912779ef9 | ||
|
|
ced63a6eb0 | ||
|
|
a5f5d36871 | ||
|
|
bd92345793 | ||
|
|
4c1b66279d | ||
|
|
fcf16eec4f | ||
|
|
508f18c29b | ||
|
|
b165e1c20c | ||
|
|
9ebcfe38bc | ||
|
|
57a585741d | ||
|
|
6173e94cc0 | ||
|
|
243aec37fd | ||
|
|
fb44e020fc | ||
|
|
81842e544b | ||
|
|
6babdab8de | ||
|
|
93d50bbee1 | ||
|
|
e6f0ecce62 | ||
|
|
aba597aa6a | ||
|
|
7444fdceff | ||
|
|
f60197e9bf | ||
|
|
4778206e3a | ||
|
|
005463c41f | ||
|
|
ae1bf1cbfb | ||
|
|
bde06621bd | ||
|
|
647acf6a68 | ||
|
|
120c0b5ca2 | ||
|
|
7e45c89fcd | ||
|
|
b7611c67bb | ||
|
|
d6ae55218f | ||
|
|
d17582d697 | ||
|
|
c3227a6352 | ||
|
|
d0c368f6a0 | ||
|
|
9aa9cc46e9 | ||
|
|
4ee045b84e | ||
|
|
2fe18c14c7 | ||
|
|
f46b002c5a | ||
|
|
65ea11b48b | ||
|
|
b2113add02 | ||
|
|
152e6ce1b9 | ||
|
|
78a5166e48 | ||
|
|
f6a4da0584 | ||
|
|
1818057c4c | ||
|
|
9c946b9808 | ||
|
|
c703106058 | ||
|
|
1bc70f09c5 | ||
|
|
d049572239 | ||
|
|
0feaed8869 | ||
|
|
7496f482ab | ||
|
|
f6faad7255 | ||
|
|
757757fa3f | ||
|
|
1fd3c11e12 | ||
|
|
b1f2273bb5 | ||
|
|
e9cf3f5ab5 |
23
.github/workflows/github-releases-to-discord.yml
vendored
Normal file
23
.github/workflows/github-releases-to-discord.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: 'github-releases-to-discord'
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
github-releases-to-discord:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Github Releases To Discord
|
||||||
|
uses: SethCohen/github-releases-to-discord@v1.13.1
|
||||||
|
with:
|
||||||
|
webhook_url: ${{ secrets.WEBHOOK_URL }}
|
||||||
|
color: '2105893'
|
||||||
|
username: 'Release Changelog'
|
||||||
|
avatar_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png'
|
||||||
|
content: '||@everyone||'
|
||||||
|
footer_title: 'Changelog'
|
||||||
|
footer_icon_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png'
|
||||||
|
footer_timestamp: true
|
||||||
19
.github/workflows/pre_release.yml
vendored
19
.github/workflows/pre_release.yml
vendored
@@ -12,11 +12,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
python-version: '3.11'
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
- name: Get EMS-ESP source code and version
|
- name: Get EMS-ESP source code and version
|
||||||
id: build_info
|
id: build_info
|
||||||
@@ -33,9 +35,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn run typesafe-i18n --no-watch
|
yarn typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn run build
|
yarn build
|
||||||
|
yarn webUI
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
@@ -45,6 +48,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
platformio run -e ci_s3
|
platformio run -e ci_s3
|
||||||
|
|
||||||
|
- name: Build E32V2 firmware
|
||||||
|
run: |
|
||||||
|
platformio run -e ci_16M
|
||||||
|
|
||||||
- name: Create a GH Release
|
- name: Create a GH Release
|
||||||
id: 'automatic_releases'
|
id: 'automatic_releases'
|
||||||
uses: 'marvinpinto/action-automatic-releases@latest'
|
uses: 'marvinpinto/action-automatic-releases@latest'
|
||||||
|
|||||||
4
.github/workflows/sonar_check.yml
vendored
4
.github/workflows/sonar_check.yml
vendored
@@ -12,9 +12,9 @@ jobs:
|
|||||||
# if: github.repository_owner == 'emsesp'
|
# if: github.repository_owner == 'emsesp'
|
||||||
# if: github.repository == 'emsesp/EMS-ESP32'
|
# if: github.repository == 'emsesp/EMS-ESP32'
|
||||||
env:
|
env:
|
||||||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory
|
BUILD_WRAPPER_OUT_DIR: bw-output
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
- name: Install sonar-scanner and build-wrapper
|
- name: Install sonar-scanner and build-wrapper
|
||||||
|
|||||||
19
.github/workflows/tagged_release.yml
vendored
19
.github/workflows/tagged_release.yml
vendored
@@ -11,11 +11,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
python-version: '3.11'
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
@@ -28,14 +30,19 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn run typesafe-i18n --no-watch
|
yarn typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn run build
|
yarn build
|
||||||
|
yarn webUI
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
platformio run -e ci
|
platformio run -e ci
|
||||||
|
|
||||||
|
- name: Build S3 firmware
|
||||||
|
run: |
|
||||||
|
platformio run -e ci_s3
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: 'marvinpinto/action-automatic-releases@latest'
|
uses: 'marvinpinto/action-automatic-releases@latest'
|
||||||
with:
|
with:
|
||||||
|
|||||||
15
.github/workflows/test_release.yml
vendored
15
.github/workflows/test_release.yml
vendored
@@ -12,11 +12,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
python-version: '3.11'
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
- name: Get EMS-ESP source code and version
|
- name: Get EMS-ESP source code and version
|
||||||
id: build_info
|
id: build_info
|
||||||
@@ -33,9 +35,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
yarn install
|
||||||
yarn run typesafe-i18n --no-watch
|
yarn typesafe-i18n --no-watch
|
||||||
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
|
||||||
yarn run build
|
yarn build
|
||||||
|
yarn webUI
|
||||||
|
|
||||||
- name: Build firmware
|
- name: Build firmware
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
17
.gitignore
vendored
17
.gitignore
vendored
@@ -2,7 +2,7 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/extensions.json
|
.vscode/extensions.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
# .vscode/settings.json
|
#.vscode/settings.json
|
||||||
|
|
||||||
# c++ compiling
|
# c++ compiling
|
||||||
.clang_complete
|
.clang_complete
|
||||||
@@ -12,11 +12,11 @@ cppcheck.out.xml
|
|||||||
# platformio
|
# platformio
|
||||||
.pio
|
.pio
|
||||||
pio_local.ini
|
pio_local.ini
|
||||||
|
*_old
|
||||||
|
|
||||||
# OS specific
|
# OS specific
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*Thumbs.db
|
*Thumbs.db
|
||||||
emsesp
|
|
||||||
|
|
||||||
# web specfic
|
# web specfic
|
||||||
build/
|
build/
|
||||||
@@ -36,12 +36,15 @@ stats.html
|
|||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
!.yarn/sdks
|
!.yarn/sdks
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
|
yarn.lock
|
||||||
|
analyse.html
|
||||||
|
interface/vite.config.ts.timestamp*
|
||||||
|
|
||||||
# scripts
|
# scripts
|
||||||
test.sh
|
test.sh
|
||||||
scripts/run.sh
|
scripts/run.sh
|
||||||
scripts/__pycache__
|
scripts/__pycache__
|
||||||
/scripts/stackdmp.txt
|
scripts/stackdmp.txt
|
||||||
|
|
||||||
# i18n generated files
|
# i18n generated files
|
||||||
interface/src/i18n/i18n-react.tsx
|
interface/src/i18n/i18n-react.tsx
|
||||||
@@ -53,8 +56,8 @@ interface/src/i18n/i18n-util.async.ts
|
|||||||
# sonar
|
# sonar
|
||||||
.scannerwork/
|
.scannerwork/
|
||||||
sonar/
|
sonar/
|
||||||
build_wrapper_output_directory/
|
bw-output/
|
||||||
|
|
||||||
|
# testing
|
||||||
|
emsesp
|
||||||
|
|
||||||
# entity dump results
|
|
||||||
# dump_entities.csv
|
|
||||||
# dump_entities.xls*
|
|
||||||
|
|||||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -2,9 +2,6 @@
|
|||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
// for the documentation about the extensions.json format
|
// for the documentation about the extensions.json format
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"arcanis.vscode-zipfs",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
|
|||||||
134
.vscode/settings.json
vendored
134
.vscode/settings.json
vendored
@@ -1,45 +1,91 @@
|
|||||||
{
|
{
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"**/.yarn": true,
|
"**/.yarn": true,
|
||||||
"**/.pnp.*": true
|
"**/.pnp.*": true
|
||||||
},
|
},
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": true
|
"source.fixAll": "explicit"
|
||||||
// "source.organizeImports": true
|
},
|
||||||
},
|
"eslint.nodePath": "interface/.yarn/sdks",
|
||||||
"eslint.nodePath": "interface/.yarn/sdks",
|
"eslint.workingDirectories": ["interface"],
|
||||||
"eslint.workingDirectories": ["interface"],
|
"prettier.prettierPath": "",
|
||||||
"prettier.prettierPath": "",
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
"typescript.tsdk": "interface/.yarn/sdks/typescript/lib",
|
"files.associations": {
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
"*.tsx": "typescriptreact",
|
||||||
"files.associations": {
|
"*.tcc": "cpp",
|
||||||
"*.tsx": "typescriptreact",
|
"optional": "cpp",
|
||||||
"*.tcc": "cpp",
|
"istream": "cpp",
|
||||||
"optional": "cpp",
|
"ostream": "cpp",
|
||||||
"istream": "cpp",
|
"ratio": "cpp",
|
||||||
"ostream": "cpp",
|
"system_error": "cpp",
|
||||||
"ratio": "cpp",
|
"array": "cpp",
|
||||||
"system_error": "cpp",
|
"functional": "cpp",
|
||||||
"array": "cpp",
|
"regex": "cpp",
|
||||||
"functional": "cpp",
|
"tuple": "cpp",
|
||||||
"regex": "cpp",
|
"type_traits": "cpp",
|
||||||
"tuple": "cpp",
|
"utility": "cpp",
|
||||||
"type_traits": "cpp",
|
"string": "cpp",
|
||||||
"utility": "cpp",
|
"string_view": "cpp",
|
||||||
"string": "cpp",
|
"atomic": "cpp",
|
||||||
"string_view": "cpp"
|
"bitset": "cpp",
|
||||||
},
|
"cctype": "cpp",
|
||||||
"todo-tree.filtering.excludeGlobs": [
|
"chrono": "cpp",
|
||||||
"**/vendor/**",
|
"clocale": "cpp",
|
||||||
"**/node_modules/**",
|
"cmath": "cpp",
|
||||||
"**/dist/**",
|
"condition_variable": "cpp",
|
||||||
"**/bower_components/**",
|
"cstdarg": "cpp",
|
||||||
"**/build/**",
|
"cstddef": "cpp",
|
||||||
"**/.vscode/**",
|
"cstdint": "cpp",
|
||||||
"**/.github/**",
|
"cstdio": "cpp",
|
||||||
"**/_output/**",
|
"cstdlib": "cpp",
|
||||||
"**/*.min.*",
|
"cstring": "cpp",
|
||||||
"**/*.map",
|
"ctime": "cpp",
|
||||||
"**/ArduinoJson/**"
|
"cwchar": "cpp",
|
||||||
]
|
"cwctype": "cpp",
|
||||||
}
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"typeinfo": "cpp"
|
||||||
|
},
|
||||||
|
"todo-tree.filtering.excludeGlobs": [
|
||||||
|
"**/vendor/**",
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/dist/**",
|
||||||
|
"**/bower_components/**",
|
||||||
|
"**/build/**",
|
||||||
|
"**/.vscode/**",
|
||||||
|
"**/.github/**",
|
||||||
|
"**/_output/**",
|
||||||
|
"**/*.min.*",
|
||||||
|
"**/*.map",
|
||||||
|
"**/ArduinoJson/**"
|
||||||
|
],
|
||||||
|
"cSpell.enableFiletypes": [
|
||||||
|
"!cpp",
|
||||||
|
"!typescript"
|
||||||
|
]
|
||||||
|
}
|
||||||
18
.vscode/tasks.json
vendored
18
.vscode/tasks.json
vendored
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
// for the documentation about the tasks.json format
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "shell",
|
|
||||||
"label": "build standalone emsesp",
|
|
||||||
"command": "make",
|
|
||||||
"args": [],
|
|
||||||
"problemMatcher": ["$gcc"],
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
205
CHANGELOG.md
205
CHANGELOG.md
@@ -5,6 +5,207 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [3.6.5] March 23 2024
|
||||||
|
|
||||||
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
|
- The Wifi Tx Power setting in Network Settings will be reset to Auto
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- thermostat boost mode and boost time [#1446](https://github.com/emsesp/EMS-ESP32/issues/1446)
|
||||||
|
- heatpump energy meters [#1463](https://github.com/emsesp/EMS-ESP32/issues/1463)
|
||||||
|
- heatpump max power [#1475](https://github.com/emsesp/EMS-ESP32/issues/1475)
|
||||||
|
- checkbox for MQTT-TLS enable [#1474](https://github.com/emsesp/EMS-ESP32/issues/1474)
|
||||||
|
- added SK (Slovak) language. Thanks @misa1515
|
||||||
|
- CPU info [#1497](https://github.com/emsesp/EMS-ESP32/pull/1497)
|
||||||
|
- Show network hostname in Web UI under Network Status
|
||||||
|
- Improved HA Discovery so each section (EMS device, Scheduler, Analog, Temperature, Custom, Shower) have their own section
|
||||||
|
- boiler Bosch C1200W, id 12, [#1536](https://github.com/emsesp/EMS-ESP32/issues/1536)
|
||||||
|
- mixer MM100 telegram 0x2CC [#1554](https://github.com/emsesp/EMS-ESP32/issues/1554)
|
||||||
|
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
|
||||||
|
- custom variables [#1423](https://github.com/emsesp/EMS-ESP32/issues/1423)
|
||||||
|
- weather compensation [#1642](https://github.com/emsesp/EMS-ESP32/issues/1642)
|
||||||
|
- env and partitions for DevKitC-1-N32R8 [#1635](https://github.com/emsesp/EMS-ESP32/discussions/1635)
|
||||||
|
- command `restart partitionname` and button long press to start with other partition [#1657](https://github.com/emsesp/EMS-ESP32/issues/1657)
|
||||||
|
- command `set service <mqtt|ota|ntp|ap> <enable|disable>` [#1663](https://github.com/emsesp/EMS-ESP32/issues/1663)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- exhaust temperature for some boilers
|
||||||
|
- add back boil2hyst [#1477](https://github.com/emsesp/EMS-ESP32/issues/1477)
|
||||||
|
- subscribed MQTT topics not detecting changes by EMS-ESP [#1494](https://github.com/emsesp/EMS-ESP32/issues/1494)
|
||||||
|
- changed HA name and grouping to be consistent [#1528](https://github.com/emsesp/EMS-ESP32/issues/1528)
|
||||||
|
- MQTT autodiscovery in Domoticz not working [#1360](https://github.com/emsesp/EMS-ESP32/issues/1528)
|
||||||
|
- dhw comfort for new ems+, [#1495](https://github.com/emsesp/EMS-ESP32/issues/1495)
|
||||||
|
- added writeable icon to Web's Custom Entity page for each entity shown in the table
|
||||||
|
- Wifi Tx Power not adjusted [#1614](https://github.com/emsesp/EMS-ESP32/issues/1614)
|
||||||
|
- MQTT discovery of custom entity doesn't consider type of data [#1587](https://github.com/emsesp/EMS-ESP32/issues/1587)
|
||||||
|
- WiFi TxPower wasn't correctly used. Added an 'Auto' setting, which is the default.
|
||||||
|
- dns w/wo IPv6 [#1644](https://github.com/emsesp/EMS-ESP32/issues/1644)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- HA don't set entity_category to Diagnostic/Configuration for EMS entities [#1459](https://github.com/emsesp/EMS-ESP32/discussions/1459)
|
||||||
|
- upgraded ArduinoJson to 7.0.0 #1538 and then 7.0.2
|
||||||
|
- small changes to the API for analog and temperature sensors
|
||||||
|
- Length of mqtt Broker adress [#1619](https://github.com/emsesp/EMS-ESP32/issues/1619)
|
||||||
|
- C++ optimizations - see <https://github.com/emsesp/EMS-ESP32/pull/1615>
|
||||||
|
- Send MQTT heartbeat immediately after connection [#1628](https://github.com/emsesp/EMS-ESP32/issues/1628)
|
||||||
|
- 16MB partitions with second nvs, larger FS, Coredump, optional factory partition
|
||||||
|
- stop fetching empty telegrams after 5 min
|
||||||
|
|
||||||
|
## [3.6.4] November 24 2023
|
||||||
|
|
||||||
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
|
Writeable Text entities have moved from type `sensor` to `text` in Home Assistant to make them also editable within an HA dashboard. Examples are `datetime`, `holidays`, `switchtime`, `vacations`, `maintenancedate`... You will need to manually remove any old discovery topics from your MQTT broker using an application like MQTT Explorer.
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- humidity for ventilation devices
|
||||||
|
- telegrams for RC100H, hc2, etc. (seen on discord, not tested)
|
||||||
|
- names for BC400, GB192i.2, read temperatures for low loss header and heatblock [#1317](https://github.com/emsesp/EMS-ESP32/discussions/1317)
|
||||||
|
- option for `forceheatingoff` [#1262](https://github.com/emsesp/EMS-ESP32/issues/1262)
|
||||||
|
- remote thermostat emulation RC100H for RC3xx [#1278](https://github.com/emsesp/EMS-ESP32/discussions/1278)
|
||||||
|
- shower_data MQTT payload contains the timestamp [#1329](https://github.com/emsesp/EMS-ESP32/issues/1329)
|
||||||
|
- HA discovery for writeable text entities [#1337](https://github.com/emsesp/EMS-ESP32/pull/1377)
|
||||||
|
- autodetect board_profile, store in nvs, add telnet command option, add E32V2
|
||||||
|
- heat pump high res energy counters [#1348, #1349. #1350](https://github.com/emsesp/EMS-ESP32/issues/1348)
|
||||||
|
- optional bssid in network settings
|
||||||
|
- extension module EM100 [#1315](https://github.com/emsesp/EMS-ESP32/discussions/1315)
|
||||||
|
- digital_out with new options for polarity and startup state
|
||||||
|
- added 'system allvalues' command that dumps all the EMS device values, plus sensors and any custom entities
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- remove command `remoteseltemp`, thermostat accept it only from remote thermostat
|
||||||
|
- shower_data MQTT payload contains the timestamp [#1329](https://github.com/emsesp/EMS-ESP32/issues/1329)
|
||||||
|
- fixed helper text in Web Device Entity dialog box for numerical ranges
|
||||||
|
- MQTT base with paths not working in HA [#1393](https://github.com/emsesp/EMS-ESP32/issues/1393)
|
||||||
|
- set/read thermostat mode for RC100-RC300, [#1440](https://github.com/emsesp/EMS-ESP32/issues/1440) [#1442](https://github.com/emsesp/EMS-ESP32/issues/1442)
|
||||||
|
- some setting commands for ems-boiler have used wrong ems+ telegram in 3.6.3
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- update to platform 6.4.0, arduino 2.0.14 / idf 4.4.6
|
||||||
|
- small changes for arduino 3.0.0 / idf 5.1 compatibility (not backward compatible to platform 6.3.2 and before)
|
||||||
|
- AP start after 10 sec, stay until station/eth connected
|
||||||
|
- tested wifi-all-channel-scan (3.6.3-dev4 a-e), removed again because of connect issues
|
||||||
|
- mqtt disconnect stops queue
|
||||||
|
|
||||||
|
## [3.6.2] October 1 2023
|
||||||
|
|
||||||
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Power entities
|
||||||
|
- Optional input of BSSID for AP connection
|
||||||
|
- Return empty json if no entries in scheduler/custom/analogsensor/temperaturesensor
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Wifi full scan to get strongest AP
|
||||||
|
- Add missing dhw tags
|
||||||
|
- Sending a dash/- to the Reset command doesn't return an error [#1308](https://github.com/emsesp/EMS-ESP32/discussions/1308)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- MQTT queue max 300 messages, check heap and maxAlloc
|
||||||
|
- API call commands are logged as WARN in the log
|
||||||
|
- Reset Command renamed to 'reset' in lowercase in EN
|
||||||
|
|
||||||
|
## [3.6.1] September 9 2023
|
||||||
|
|
||||||
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
|
- `shower_data` MQTT topic shows duration is seconds (was previously a full english sentence)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Show WiFi rssi in Network Status Page, show quality as color
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Issue in espMqttClient causing a memory leak when MQTT broker is disconnected due to network unavailability [#1264](https://github.com/emsesp/EMS-ESP32/issues/1264)
|
||||||
|
- Using MQTT enum values correctly formatted in MQTT Discovery [#1280](https://github.com/emsesp/EMS-ESP32/issues/1280)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- MQTT free mem check set to 60 kb
|
||||||
|
- Small cosmetic changes to Searching in Customization web page
|
||||||
|
- Updated to espressif32@6.4.0
|
||||||
|
|
||||||
|
# [3.6.0] August 13 2023
|
||||||
|
|
||||||
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
|
There are breaking changes between 3.5.x and earlier versions of 3.6.0. Please read carefully before applying the update.
|
||||||
|
|
||||||
|
- The sensors have been renamed. `dallassensor` is now `temperaturesensor` in the MQTT topic and named `ts` in the Customizations file. Likewise `analogs` is now `analogsensor` in MQTT and called `as` in the Customizations file. If you have previous customizations you will need to manually update by downloading, changing the JSON file and uploading. It's also recommended cleaning up any old MQTT topics from your broker using an application like MQTTExplorer.
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Workaround for better Domoticz MQTT integration? [#904](https://github.com/emsesp/EMS-ESP32/issues/904)
|
||||||
|
- Show MAC address without connecting to network enhancement [#933](https://github.com/emsesp/EMS-ESP32/issues/933)
|
||||||
|
- Warn user in WebUI of unsaved changes [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
||||||
|
- Detect old Tado thermostat, device-id 0x19, no entities
|
||||||
|
- Some more HM200 entities [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
|
||||||
|
- Added Scheduler [#701](https://github.com/emsesp/EMS-ESP32/issues/701)
|
||||||
|
- Added Custom Entities read/write from EMS bus
|
||||||
|
- Build S3 binary with github actions
|
||||||
|
- Greenstar HIU [#1158](https://github.com/emsesp/EMS-ESP32/issues/1158)
|
||||||
|
- AM200 code 10 [#1161](https://github.com/emsesp/EMS-ESP32/issues/1161)
|
||||||
|
- Ventilation device (Logavent HRV176) [#1172](https://github.com/emsesp/EMS-ESP32/issues/1172)
|
||||||
|
- Turn ETH off on wifi connect [#1167](https://github.com/emsesp/EMS-ESP32/issues/1167)
|
||||||
|
- Support for multiple EMS-ESPs with HA [#1196](https://github.com/emsesp/EMS-ESP32/issues/1196)
|
||||||
|
- Italian translation [#1199](https://github.com/emsesp/EMS-ESP32/issues/1199)
|
||||||
|
- Turkish language support [#1076](https://github.com/emsesp/EMS-ESP32/issues/1076)
|
||||||
|
- Buderus GB182 - HC1 mode change not work bug [#1193](https://github.com/emsesp/EMS-ESP32/issues/1193)
|
||||||
|
- Minimal flow temperature enhancement [#1192](https://github.com/emsesp/EMS-ESP32/issues/1192)
|
||||||
|
- Roomtemperature Switching Difference enhancement [#1191](https://github.com/emsesp/EMS-ESP32/issues/1191)
|
||||||
|
- Dew Point Temperature Difference enhancement [#1190](https://github.com/emsesp/EMS-ESP32/issues/1190)
|
||||||
|
- Control of heating circuit mode enhancement [#1187](https://github.com/emsesp/EMS-ESP32/issues/1187)
|
||||||
|
- Warn user in WebUI of unsaved changes enhancement [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
||||||
|
- Create safebuild app to fit into factory partition to give ESP32 more flash memory enhancement [#608](https://github.com/emsesp/EMS-ESP32/issues/608)
|
||||||
|
- Support ESP32 S2, C3 mini and S3 [#605](https://github.com/emsesp/EMS-ESP32/issues/605)
|
||||||
|
- Support Buderus AM200 [#1161](https://github.com/emsesp/EMS-ESP32/issues/1161)
|
||||||
|
- Custom telegram handler [#1155](https://github.com/emsesp/EMS-ESP32/issues/1155)
|
||||||
|
- Added support for TLS in MQTT (ESP32-S3 only) [#1178](https://github.com/emsesp/EMS-ESP32/issues/1178)
|
||||||
|
- Boardprofile BBQKees Gateway S3
|
||||||
|
- Custom entity type RAW [#1212](https://github.com/emsesp/EMS-ESP32/discussions/1212)
|
||||||
|
- API command response [#1212](https://github.com/emsesp/EMS-ESP32/discussions/1212)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- HA-discovery for analog sensor commands [#1035](https://github.com/emsesp/EMS-ESP32/issues/1035)
|
||||||
|
- Enum order of RC3x nofrost mode
|
||||||
|
- Heartbeat interval
|
||||||
|
- Exhaust temperature always zero on GB125/MC110/RC310 bug [#1147](https://github.com/emsesp/EMS-ESP32/issues/1147)
|
||||||
|
- thermostat modetype is not changing when mode changes (e.g. to night) bugSomething isn't working [#1098](https://github.com/emsesp/EMS-ESP32/issues/1098)
|
||||||
|
- NTP: cant apply changed timezone [#1182](https://github.com/emsesp/EMS-ESP32/issues/1182)
|
||||||
|
- Missing Status of VS1 for Buderus SM200 enhancement [#1034](https://github.com/emsesp/EMS-ESP32/issues/1034)
|
||||||
|
- Allowed gpios for S3
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Optional upgrade to platform-espressif32 6.3.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
|
||||||
|
- Optimize WebUI rendering when using Dialog Boxes [#1116](https://github.com/emsesp/EMS-ESP32/issues/1116)
|
||||||
|
- Optimize Web libraries to reduce bundle size (3.6.x) [#1112](https://github.com/emsesp/EMS-ESP32/issues/1112)
|
||||||
|
- Use [espMqttClient](https://github.com/bertmelis/espMqttClient) with integrated queue [#1178](https://github.com/emsesp/EMS-ESP32/issues/1178)
|
||||||
|
- Move Sensors from Web dashboard to it's own tab enhancement [#1170](https://github.com/emsesp/EMS-ESP32/issues/1170)
|
||||||
|
- Optimize WebUI dashboard data [#1169](https://github.com/emsesp/EMS-ESP32/issues/1169)
|
||||||
|
- Replace React core library with Preact to save on memory footprint
|
||||||
|
- Response to `system/send` raw reads gives combined data for telegrams with more parts
|
||||||
|
|
||||||
# [3.5.0] February 6 2023
|
# [3.5.0] February 6 2023
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
@@ -85,7 +286,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- fix Table resizing in WebUI [#519](https://github.com/emsesp/EMS-ESP32/issues/519)
|
- fix Table resizing in WebUI [#519](https://github.com/emsesp/EMS-ESP32/issues/519)
|
||||||
- allow larger customization files [#570](https://github.com/emsesp/EMS-ESP32/issues/570)
|
- allow larger customization files [#570](https://github.com/emsesp/EMS-ESP32/issues/570)
|
||||||
- losing entitiy wwcomfort [#581](https://github.com/emsesp/EMS-ESP32/issues/581)
|
- losing entity wwcomfort [#581](https://github.com/emsesp/EMS-ESP32/issues/581)
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
@@ -112,7 +313,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- WebUI optimizations, updated look&feel and better performance [#124](https://github.com/emsesp/EMS-ESP32/issues/124)
|
- WebUI optimizations, updated look&feel and better performance [#124](https://github.com/emsesp/EMS-ESP32/issues/124)
|
||||||
- Auto refresh of WebUI after successful firmware upload [#178](https://github.com/emsesp/EMS-ESP32/issues/178)
|
- Auto refresh of WebUI after successful firmware upload [#178](https://github.com/emsesp/EMS-ESP32/issues/178)
|
||||||
- New Customization Service in WebUI. First feature is the ability to enable/disabled Enitites (device values) from EMS devices [#206](https://github.com/emsesp/EMS-ESP32/issues/206)
|
- New Customization Service in WebUI. First feature is the ability to enable/disabled Entities (device values) from EMS devices [#206](https://github.com/emsesp/EMS-ESP32/issues/206)
|
||||||
- Option to disable Telnet Console [#209](https://github.com/emsesp/EMS-ESP32/issues/209)
|
- Option to disable Telnet Console [#209](https://github.com/emsesp/EMS-ESP32/issues/209)
|
||||||
- Added Hide SSID, Max Clients and Preferred Channel to Access Point
|
- Added Hide SSID, Max Clients and Preferred Channel to Access Point
|
||||||
- Merged in MichaelDvP's changes like Fahrenheit conversion, publish single (for IOBroker) and a few other critical optimizations
|
- Merged in MichaelDvP's changes like Fahrenheit conversion, publish single (for IOBroker) and a few other critical optimizations
|
||||||
|
|||||||
@@ -1,70 +1,23 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
# [3.6.0]
|
## [3.7.0]
|
||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
## **IMPORTANT! BREAKING CHANGES**
|
||||||
|
|
||||||
There are breaking changes between 3.5.x and earlier versions of 3.6.0. Please read carefully before applying the update.
|
- new device WATER shows dhw entities from MM100 and SM100 in dhw setting
|
||||||
|
|
||||||
- The sensors have been renamed. `dallassensor` is now `temperaturesensor` in the MQTT topic and named `ts` in the Customizations file. Likewise `analogs` is now `analogsensor` in MQTT and called `as` in the Customizations file. If you have previous customizations you will need to manually update by downloading, changing the JSON file and uploading. It's also recommended cleaning up any old MQTT topics from your broker using an application like MQTTExplorer.
|
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Workaround for better Domoticz MQTT intergration? [#904](https://github.com/emsesp/EMS-ESP32/issues/904)
|
- some more entities for dhw with SM100 module
|
||||||
- Show MAC address without connecting to network enhancement [#933](https://github.com/emsesp/EMS-ESP32/issues/933)
|
- thermostat second dhw circuit [#1634](https://github.com/emsesp/EMS-ESP32/issues/1634)
|
||||||
- Warn user in WebUI of unsaved changes [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
- remote thermostat emulation for RC100H, RC200 and FB10 [#1287](https://github.com/emsesp/EMS-ESP32/discussions/1287), [#1602](https://github.com/emsesp/EMS-ESP32/discussions/1602), [#1551](https://github.com/emsesp/EMS-ESP32/discussions/1551)
|
||||||
- Detect old Tado thermostat, device-id 0x19, no entities
|
- heatpump dhw stop temperatures [#1624](https://github.com/emsesp/EMS-ESP32/issues/1624)
|
||||||
- Some more HM200 entities [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
|
|
||||||
- Added Scheduler [#701](https://github.com/emsesp/EMS-ESP32/issues/701)
|
|
||||||
- Added Custom Entities read/write from EMS bus
|
|
||||||
- Build S3 binary with github actions
|
|
||||||
- Greenstar HIU [#1158](https://github.com/emsesp/EMS-ESP32/issues/1158)
|
|
||||||
- AM200 code 10 [#1161](https://github.com/emsesp/EMS-ESP32/issues/1161)
|
|
||||||
- Ventilation device (Logavent HRV176) [#1172](https://github.com/emsesp/EMS-ESP32/issues/1172)
|
|
||||||
- Turn ETH off on wifi connect [#1167](https://github.com/emsesp/EMS-ESP32/issues/1167)
|
|
||||||
- Support for multiple EMS-ESPs with HA [#1196](https://github.com/emsesp/EMS-ESP32/issues/1196)
|
|
||||||
- Italian translation [#1199](https://github.com/emsesp/EMS-ESP32/issues/1199)
|
|
||||||
- Turkish language support [#1076](https://github.com/emsesp/EMS-ESP32/issues/1076)
|
|
||||||
- Buderus GB182 - HC1 mode change not work bug [#1193](https://github.com/emsesp/EMS-ESP32/issues/1193)
|
|
||||||
- Minimal flow temperature enhancement [#1192](https://github.com/emsesp/EMS-ESP32/issues/1192)
|
|
||||||
- Roomtemperature Switching Difference enhancement [#1191](https://github.com/emsesp/EMS-ESP32/issues/1191)
|
|
||||||
- Dew Point Temperature Difference enhancement [#1190](https://github.com/emsesp/EMS-ESP32/issues/1190)
|
|
||||||
- Control of heating circuit mode enhancement [#1187](https://github.com/emsesp/EMS-ESP32/issues/1187)
|
|
||||||
- Warn user in WebUI of unsaved changes enhancement [#911](https://github.com/emsesp/EMS-ESP32/issues/911)
|
|
||||||
- Create safebuild app to fit into factory partition to give ESP32 more flash memory enhancement [#608](https://github.com/emsesp/EMS-ESP32/issues/608)
|
|
||||||
- Support ESP32 S2, C3 mini and S3 [#605](https://github.com/emsesp/EMS-ESP32/issues/605)
|
|
||||||
- Support Buderus AM200 [#1161](https://github.com/emsesp/EMS-ESP32/issues/1161)
|
|
||||||
- Custom telegram handler [#1155](https://github.com/emsesp/EMS-ESP32/issues/1155)
|
|
||||||
- Added support for TLS in MQTT (ESP32-S3 only) [#1178](https://github.com/emsesp/EMS-ESP32/issues/1178)
|
|
||||||
- Boardprofile BBQKees Gateway S3
|
|
||||||
- Custom entity type RAW [#1212](https://github.com/emsesp/EMS-ESP32/discussions/1212)
|
|
||||||
- API command response [#1212](https://github.com/emsesp/EMS-ESP32/discussions/1212)
|
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- HA-discovery for analog sensor commands [#1035](https://github.com/emsesp/EMS-ESP32/issues/1035)
|
|
||||||
- Enum order of RC3x nofrost mode
|
|
||||||
- Heartbeat interval
|
|
||||||
- Exhaust temperature always zero on GB125/MC110/RC310 bug [#1147](https://github.com/emsesp/EMS-ESP32/issues/1147)
|
|
||||||
- thermostat modetype is not changing when mode changes (e.g. to night) bugSomething isn't working [#1098](https://github.com/emsesp/EMS-ESP32/issues/1098)
|
|
||||||
- NTP: cant apply changed timezone [#1182](https://github.com/emsesp/EMS-ESP32/issues/1182)
|
|
||||||
- Missing Status of VS1 for Buderus SM200 enhancement [#1034](https://github.com/emsesp/EMS-ESP32/issues/1034)
|
|
||||||
- Allowed gpios for S3
|
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- Optional upgrade to platform-espressif32 6.3.0 (after 5.3.0) [#862](https://github.com/emsesp/EMS-ESP32/issues/862)
|
- use flag for BC400 compatible thermostats, manage different mode settings
|
||||||
- Use byte 3 for detection RC30 active heatingcircuit [#786](https://github.com/emsesp/EMS-ESP32/issues/786)
|
- use factory partition for 16M flash
|
||||||
- Write repeated selflowtemp if tx-queue is empty without verify [#954](https://github.com/emsesp/EMS-ESP32/issues/954)
|
- store digital out states to nvs
|
||||||
- HA discovery recreate after disconnect by device [#1067](https://github.com/emsesp/EMS-ESP32/issues/1067)
|
- Refresh UI - moving settings to one location [#1665](https://github.com/emsesp/EMS-ESP32/issues/1665)
|
||||||
- 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
|
|
||||||
- Optimize WebUI rendering when using Dialog Boxes [#1116](https://github.com/emsesp/EMS-ESP32/issues/1116)
|
|
||||||
- Optimize Web libraries to reduce bundle size (3.6.x) [#1112](https://github.com/emsesp/EMS-ESP32/issues/1112)
|
|
||||||
- Use [espMqttClient](https://github.com/bertmelis/espMqttClient) with integrated queue [#1178](https://github.com/emsesp/EMS-ESP32/issues/1178)
|
|
||||||
- Move Sensors from Web dashboard to it's own tab enhancement [#1170](https://github.com/emsesp/EMS-ESP32/issues/1170)
|
|
||||||
- Optimize WebUI dashboard data [#1169](https://github.com/emsesp/EMS-ESP32/issues/1169)
|
|
||||||
- Replace React core library with Preact to save on memory footprint
|
|
||||||
- Response to `system/send` raw reads gives combined data for telegrams with more parts
|
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -42,7 +42,7 @@ DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DAR
|
|||||||
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
|
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
|
||||||
DEFINES += $(ARGS)
|
DEFINES += $(ARGS)
|
||||||
|
|
||||||
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.6.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
@@ -81,7 +81,7 @@ CPPFLAGS += -g3
|
|||||||
CPPFLAGS += -Os
|
CPPFLAGS += -Os
|
||||||
|
|
||||||
CFLAGS += $(CPPFLAGS)
|
CFLAGS += $(CPPFLAGS)
|
||||||
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture
|
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-unused-lambda-capture -Wno-sign-compare
|
||||||
|
|
||||||
CXXFLAGS += $(CFLAGS) -MMD
|
CXXFLAGS += $(CFLAGS) -MMD
|
||||||
|
|
||||||
|
|||||||
2338
dump_entities.csv
2338
dump_entities.csv
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
|||||||
# Name, Type, SubType, Offset, Size, Flags
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
nvs, data, nvs, 0x9000, 0x5000,
|
nvs, data, nvs, 0x9000, 0x005000,
|
||||||
otadata, data, ota, , 0x2000,
|
otadata, data, ota, , 0x002000,
|
||||||
app0, app, ota_0, , 0x7F0000,
|
boot, app, factory, , 0x280000,
|
||||||
app1, app, ota_1, , 0x7F0000,
|
app0, app, ota_0, , 0x590000,
|
||||||
spiffs, data, spiffs, , 64K,
|
app1, app, ota_1, , 0x590000,
|
||||||
|
nvs1, data, nvs, , 0x040000,
|
||||||
|
spiffs, data, spiffs, , 0x200000,
|
||||||
|
coredump, data, coredump,, 0x010000,
|
||||||
|
8
esp32_partition_32M.csv
Normal file
8
esp32_partition_32M.csv
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x005000,
|
||||||
|
otadata, data, ota, , 0x002000,
|
||||||
|
app0, app, ota_0, , 0xDD0000,
|
||||||
|
app1, app, ota_1, , 0xDD0000,
|
||||||
|
nvs1, data, nvs, , 0x040000,
|
||||||
|
spiffs, data, spiffs, , 0x400000,
|
||||||
|
coredump, data, coredump,, 0x010000,
|
||||||
|
@@ -36,7 +36,6 @@ build_flags =
|
|||||||
-D FACTORY_MQTT_PORT=1883
|
-D FACTORY_MQTT_PORT=1883
|
||||||
-D FACTORY_MQTT_USERNAME=\"\"
|
-D FACTORY_MQTT_USERNAME=\"\"
|
||||||
-D FACTORY_MQTT_PASSWORD=\"\"
|
-D FACTORY_MQTT_PASSWORD=\"\"
|
||||||
-D FACTORY_MQTT_CLIENT_ID=\"ems-esp\"
|
|
||||||
-D FACTORY_MQTT_KEEP_ALIVE=60
|
-D FACTORY_MQTT_KEEP_ALIVE=60
|
||||||
-D FACTORY_MQTT_CLEAN_SESSION=false
|
-D FACTORY_MQTT_CLEAN_SESSION=false
|
||||||
-D FACTORY_MQTT_MAX_TOPIC_LENGTH=128
|
-D FACTORY_MQTT_MAX_TOPIC_LENGTH=128
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"airbnb/hooks",
|
// "airbnb/hooks",
|
||||||
"airbnb-typescript",
|
// "airbnb-typescript",
|
||||||
"plugin:react/recommended",
|
"plugin:react/recommended",
|
||||||
"plugin:react/jsx-runtime",
|
"plugin:react/jsx-runtime",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"adapter": "react",
|
"adapter": "react",
|
||||||
"baseLocale": "pl",
|
"baseLocale": "pl",
|
||||||
"$schema": "https://unpkg.com/typesafe-i18n@5.26.0/schema/typesafe-i18n.json"
|
"$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
873
interface/.yarn/releases/yarn-3.4.1.cjs
vendored
873
interface/.yarn/releases/yarn-3.4.1.cjs
vendored
File diff suppressed because one or more lines are too long
893
interface/.yarn/releases/yarn-4.1.1.cjs
vendored
Executable file
893
interface/.yarn/releases/yarn-4.1.1.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
20
interface/.yarn/sdks/eslint/bin/eslint.js
vendored
20
interface/.yarn/sdks/eslint/bin/eslint.js
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require eslint/bin/eslint.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real eslint/bin/eslint.js your application uses
|
|
||||||
module.exports = absRequire(`eslint/bin/eslint.js`);
|
|
||||||
20
interface/.yarn/sdks/eslint/lib/api.js
vendored
20
interface/.yarn/sdks/eslint/lib/api.js
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require eslint
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real eslint your application uses
|
|
||||||
module.exports = absRequire(`eslint`);
|
|
||||||
6
interface/.yarn/sdks/eslint/package.json
vendored
6
interface/.yarn/sdks/eslint/package.json
vendored
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "eslint",
|
|
||||||
"version": "8.36.0-sdk",
|
|
||||||
"main": "./lib/api.js",
|
|
||||||
"type": "commonjs"
|
|
||||||
}
|
|
||||||
5
interface/.yarn/sdks/integrations.yml
vendored
5
interface/.yarn/sdks/integrations.yml
vendored
@@ -1,5 +0,0 @@
|
|||||||
# This file is automatically generated by @yarnpkg/sdks.
|
|
||||||
# Manual changes might be lost!
|
|
||||||
|
|
||||||
integrations:
|
|
||||||
- vscode
|
|
||||||
20
interface/.yarn/sdks/prettier/index.js
vendored
20
interface/.yarn/sdks/prettier/index.js
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require prettier/index.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real prettier/index.js your application uses
|
|
||||||
module.exports = absRequire(`prettier/index.js`);
|
|
||||||
6
interface/.yarn/sdks/prettier/package.json
vendored
6
interface/.yarn/sdks/prettier/package.json
vendored
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "prettier",
|
|
||||||
"version": "2.8.7-sdk",
|
|
||||||
"main": "./index.js",
|
|
||||||
"type": "commonjs"
|
|
||||||
}
|
|
||||||
20
interface/.yarn/sdks/typescript/bin/tsc
vendored
20
interface/.yarn/sdks/typescript/bin/tsc
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/bin/tsc
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/bin/tsc your application uses
|
|
||||||
module.exports = absRequire(`typescript/bin/tsc`);
|
|
||||||
20
interface/.yarn/sdks/typescript/bin/tsserver
vendored
20
interface/.yarn/sdks/typescript/bin/tsserver
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/bin/tsserver
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/bin/tsserver your application uses
|
|
||||||
module.exports = absRequire(`typescript/bin/tsserver`);
|
|
||||||
20
interface/.yarn/sdks/typescript/lib/tsc.js
vendored
20
interface/.yarn/sdks/typescript/lib/tsc.js
vendored
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/lib/tsc.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/lib/tsc.js your application uses
|
|
||||||
module.exports = absRequire(`typescript/lib/tsc.js`);
|
|
||||||
223
interface/.yarn/sdks/typescript/lib/tsserver.js
vendored
223
interface/.yarn/sdks/typescript/lib/tsserver.js
vendored
@@ -1,223 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
const moduleWrapper = tsserver => {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
return tsserver;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {isAbsolute} = require(`path`);
|
|
||||||
const pnpApi = require(`pnpapi`);
|
|
||||||
|
|
||||||
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
|
|
||||||
const isPortal = str => str.startsWith("portal:/");
|
|
||||||
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
|
|
||||||
|
|
||||||
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
|
|
||||||
return `${locator.name}@${locator.reference}`;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
|
|
||||||
// doesn't understand. This layer makes sure to remove the protocol
|
|
||||||
// before forwarding it to TS, and to add it back on all returned paths.
|
|
||||||
|
|
||||||
function toEditorPath(str) {
|
|
||||||
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
|
|
||||||
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
|
|
||||||
// We also take the opportunity to turn virtual paths into physical ones;
|
|
||||||
// this makes it much easier to work with workspaces that list peer
|
|
||||||
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
|
|
||||||
// file instances instead of the real ones.
|
|
||||||
//
|
|
||||||
// We only do this to modules owned by the the dependency tree roots.
|
|
||||||
// This avoids breaking the resolution when jumping inside a vendor
|
|
||||||
// with peer dep (otherwise jumping into react-dom would show resolution
|
|
||||||
// errors on react).
|
|
||||||
//
|
|
||||||
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
|
|
||||||
if (resolved) {
|
|
||||||
const locator = pnpApi.findPackageLocator(resolved);
|
|
||||||
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
|
|
||||||
str = resolved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = normalize(str);
|
|
||||||
|
|
||||||
if (str.match(/\.zip\//)) {
|
|
||||||
switch (hostInfo) {
|
|
||||||
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
|
|
||||||
// VSCode only adds it automatically for supported schemes,
|
|
||||||
// so we have to do it manually for the `zip` scheme.
|
|
||||||
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
|
|
||||||
//
|
|
||||||
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
|
|
||||||
//
|
|
||||||
// 2021-10-08: VSCode changed the format in 1.61.
|
|
||||||
// Before | ^zip:/c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
// 2022-04-06: VSCode changed the format in 1.66.
|
|
||||||
// Before | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip/c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
// 2022-05-06: VSCode changed the format in 1.68
|
|
||||||
// Before | ^/zip/c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
case `vscode <1.61`: {
|
|
||||||
str = `^zip:${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode <1.66`: {
|
|
||||||
str = `^/zip/${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode <1.68`: {
|
|
||||||
str = `^/zip${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode`: {
|
|
||||||
str = `^/zip/${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// To make "go to definition" work,
|
|
||||||
// We have to resolve the actual file system path from virtual path
|
|
||||||
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
|
|
||||||
case `coc-nvim`: {
|
|
||||||
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
|
||||||
str = resolve(`zipfile:${str}`);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
|
|
||||||
// We have to resolve the actual file system path from virtual path,
|
|
||||||
// everything else is up to neovim
|
|
||||||
case `neovim`: {
|
|
||||||
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
|
||||||
str = `zipfile://${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
str = `zip:${str}`;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromEditorPath(str) {
|
|
||||||
switch (hostInfo) {
|
|
||||||
case `coc-nvim`: {
|
|
||||||
str = str.replace(/\.zip::/, `.zip/`);
|
|
||||||
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
|
|
||||||
// So in order to convert it back, we use .* to match all the thing
|
|
||||||
// before `zipfile:`
|
|
||||||
return process.platform === `win32`
|
|
||||||
? str.replace(/^.*zipfile:\//, ``)
|
|
||||||
: str.replace(/^.*zipfile:/, ``);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `neovim`: {
|
|
||||||
str = str.replace(/\.zip::/, `.zip/`);
|
|
||||||
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
|
|
||||||
return str.replace(/^zipfile:\/\//, ``);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode`:
|
|
||||||
default: {
|
|
||||||
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force enable 'allowLocalPluginLoads'
|
|
||||||
// TypeScript tries to resolve plugins using a path relative to itself
|
|
||||||
// which doesn't work when using the global cache
|
|
||||||
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
|
|
||||||
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
|
|
||||||
// TypeScript already does local loads and if this code is running the user trusts the workspace
|
|
||||||
// https://github.com/microsoft/vscode/issues/45856
|
|
||||||
const ConfiguredProject = tsserver.server.ConfiguredProject;
|
|
||||||
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
|
|
||||||
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
|
|
||||||
this.projectService.allowLocalPluginLoads = true;
|
|
||||||
return originalEnablePluginsWithOptions.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
// And here is the point where we hijack the VSCode <-> TS communications
|
|
||||||
// by adding ourselves in the middle. We locate everything that looks
|
|
||||||
// like an absolute path of ours and normalize it.
|
|
||||||
|
|
||||||
const Session = tsserver.server.Session;
|
|
||||||
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
|
|
||||||
let hostInfo = `unknown`;
|
|
||||||
|
|
||||||
Object.assign(Session.prototype, {
|
|
||||||
onMessage(/** @type {string | object} */ message) {
|
|
||||||
const isStringMessage = typeof message === 'string';
|
|
||||||
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
|
|
||||||
|
|
||||||
if (
|
|
||||||
parsedMessage != null &&
|
|
||||||
typeof parsedMessage === `object` &&
|
|
||||||
parsedMessage.arguments &&
|
|
||||||
typeof parsedMessage.arguments.hostInfo === `string`
|
|
||||||
) {
|
|
||||||
hostInfo = parsedMessage.arguments.hostInfo;
|
|
||||||
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
|
|
||||||
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
|
|
||||||
// The RegExp from https://semver.org/ but without the caret at the start
|
|
||||||
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
|
|
||||||
) ?? []).map(Number)
|
|
||||||
|
|
||||||
if (major === 1) {
|
|
||||||
if (minor < 61) {
|
|
||||||
hostInfo += ` <1.61`;
|
|
||||||
} else if (minor < 66) {
|
|
||||||
hostInfo += ` <1.66`;
|
|
||||||
} else if (minor < 68) {
|
|
||||||
hostInfo += ` <1.68`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
|
|
||||||
return typeof value === 'string' ? fromEditorPath(value) : value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return originalOnMessage.call(
|
|
||||||
this,
|
|
||||||
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
send(/** @type {any} */ msg) {
|
|
||||||
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
|
|
||||||
return typeof value === `string` ? toEditorPath(value) : value;
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return tsserver;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/lib/tsserver.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/lib/tsserver.js your application uses
|
|
||||||
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`));
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
const moduleWrapper = tsserver => {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
return tsserver;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {isAbsolute} = require(`path`);
|
|
||||||
const pnpApi = require(`pnpapi`);
|
|
||||||
|
|
||||||
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
|
|
||||||
const isPortal = str => str.startsWith("portal:/");
|
|
||||||
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
|
|
||||||
|
|
||||||
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
|
|
||||||
return `${locator.name}@${locator.reference}`;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
|
|
||||||
// doesn't understand. This layer makes sure to remove the protocol
|
|
||||||
// before forwarding it to TS, and to add it back on all returned paths.
|
|
||||||
|
|
||||||
function toEditorPath(str) {
|
|
||||||
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
|
|
||||||
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
|
|
||||||
// We also take the opportunity to turn virtual paths into physical ones;
|
|
||||||
// this makes it much easier to work with workspaces that list peer
|
|
||||||
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
|
|
||||||
// file instances instead of the real ones.
|
|
||||||
//
|
|
||||||
// We only do this to modules owned by the the dependency tree roots.
|
|
||||||
// This avoids breaking the resolution when jumping inside a vendor
|
|
||||||
// with peer dep (otherwise jumping into react-dom would show resolution
|
|
||||||
// errors on react).
|
|
||||||
//
|
|
||||||
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
|
|
||||||
if (resolved) {
|
|
||||||
const locator = pnpApi.findPackageLocator(resolved);
|
|
||||||
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
|
|
||||||
str = resolved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = normalize(str);
|
|
||||||
|
|
||||||
if (str.match(/\.zip\//)) {
|
|
||||||
switch (hostInfo) {
|
|
||||||
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
|
|
||||||
// VSCode only adds it automatically for supported schemes,
|
|
||||||
// so we have to do it manually for the `zip` scheme.
|
|
||||||
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
|
|
||||||
//
|
|
||||||
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
|
|
||||||
//
|
|
||||||
// 2021-10-08: VSCode changed the format in 1.61.
|
|
||||||
// Before | ^zip:/c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
// 2022-04-06: VSCode changed the format in 1.66.
|
|
||||||
// Before | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip/c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
// 2022-05-06: VSCode changed the format in 1.68
|
|
||||||
// Before | ^/zip/c:/foo/bar.zip/package.json
|
|
||||||
// After | ^/zip//c:/foo/bar.zip/package.json
|
|
||||||
//
|
|
||||||
case `vscode <1.61`: {
|
|
||||||
str = `^zip:${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode <1.66`: {
|
|
||||||
str = `^/zip/${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode <1.68`: {
|
|
||||||
str = `^/zip${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode`: {
|
|
||||||
str = `^/zip/${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// To make "go to definition" work,
|
|
||||||
// We have to resolve the actual file system path from virtual path
|
|
||||||
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
|
|
||||||
case `coc-nvim`: {
|
|
||||||
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
|
||||||
str = resolve(`zipfile:${str}`);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
|
|
||||||
// We have to resolve the actual file system path from virtual path,
|
|
||||||
// everything else is up to neovim
|
|
||||||
case `neovim`: {
|
|
||||||
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
|
|
||||||
str = `zipfile://${str}`;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
str = `zip:${str}`;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromEditorPath(str) {
|
|
||||||
switch (hostInfo) {
|
|
||||||
case `coc-nvim`: {
|
|
||||||
str = str.replace(/\.zip::/, `.zip/`);
|
|
||||||
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
|
|
||||||
// So in order to convert it back, we use .* to match all the thing
|
|
||||||
// before `zipfile:`
|
|
||||||
return process.platform === `win32`
|
|
||||||
? str.replace(/^.*zipfile:\//, ``)
|
|
||||||
: str.replace(/^.*zipfile:/, ``);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `neovim`: {
|
|
||||||
str = str.replace(/\.zip::/, `.zip/`);
|
|
||||||
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
|
|
||||||
return str.replace(/^zipfile:\/\//, ``);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case `vscode`:
|
|
||||||
default: {
|
|
||||||
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force enable 'allowLocalPluginLoads'
|
|
||||||
// TypeScript tries to resolve plugins using a path relative to itself
|
|
||||||
// which doesn't work when using the global cache
|
|
||||||
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
|
|
||||||
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
|
|
||||||
// TypeScript already does local loads and if this code is running the user trusts the workspace
|
|
||||||
// https://github.com/microsoft/vscode/issues/45856
|
|
||||||
const ConfiguredProject = tsserver.server.ConfiguredProject;
|
|
||||||
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
|
|
||||||
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
|
|
||||||
this.projectService.allowLocalPluginLoads = true;
|
|
||||||
return originalEnablePluginsWithOptions.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
// And here is the point where we hijack the VSCode <-> TS communications
|
|
||||||
// by adding ourselves in the middle. We locate everything that looks
|
|
||||||
// like an absolute path of ours and normalize it.
|
|
||||||
|
|
||||||
const Session = tsserver.server.Session;
|
|
||||||
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
|
|
||||||
let hostInfo = `unknown`;
|
|
||||||
|
|
||||||
Object.assign(Session.prototype, {
|
|
||||||
onMessage(/** @type {string | object} */ message) {
|
|
||||||
const isStringMessage = typeof message === 'string';
|
|
||||||
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
|
|
||||||
|
|
||||||
if (
|
|
||||||
parsedMessage != null &&
|
|
||||||
typeof parsedMessage === `object` &&
|
|
||||||
parsedMessage.arguments &&
|
|
||||||
typeof parsedMessage.arguments.hostInfo === `string`
|
|
||||||
) {
|
|
||||||
hostInfo = parsedMessage.arguments.hostInfo;
|
|
||||||
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
|
|
||||||
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
|
|
||||||
// The RegExp from https://semver.org/ but without the caret at the start
|
|
||||||
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
|
|
||||||
) ?? []).map(Number)
|
|
||||||
|
|
||||||
if (major === 1) {
|
|
||||||
if (minor < 61) {
|
|
||||||
hostInfo += ` <1.61`;
|
|
||||||
} else if (minor < 66) {
|
|
||||||
hostInfo += ` <1.66`;
|
|
||||||
} else if (minor < 68) {
|
|
||||||
hostInfo += ` <1.68`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
|
|
||||||
return typeof value === 'string' ? fromEditorPath(value) : value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return originalOnMessage.call(
|
|
||||||
this,
|
|
||||||
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
send(/** @type {any} */ msg) {
|
|
||||||
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
|
|
||||||
return typeof value === `string` ? toEditorPath(value) : value;
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return tsserver;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/lib/tsserverlibrary.js your application uses
|
|
||||||
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`));
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const {existsSync} = require(`fs`);
|
|
||||||
const {createRequire} = require(`module`);
|
|
||||||
const {resolve} = require(`path`);
|
|
||||||
|
|
||||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
|
||||||
|
|
||||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
|
||||||
const absRequire = createRequire(absPnpApiPath);
|
|
||||||
|
|
||||||
if (existsSync(absPnpApiPath)) {
|
|
||||||
if (!process.versions.pnp) {
|
|
||||||
// Setup the environment to be able to require typescript/lib/typescript.js
|
|
||||||
require(absPnpApiPath).setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to the real typescript/lib/typescript.js your application uses
|
|
||||||
module.exports = absRequire(`typescript/lib/typescript.js`);
|
|
||||||
6
interface/.yarn/sdks/typescript/package.json
vendored
6
interface/.yarn/sdks/typescript/package.json
vendored
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "typescript",
|
|
||||||
"version": "5.0.2-sdk",
|
|
||||||
"main": "./lib/typescript.js",
|
|
||||||
"type": "commonjs"
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,7 @@
|
|||||||
plugins:
|
compressionLevel: mixed
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
|
||||||
spec: '@yarnpkg/plugin-typescript'
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-3.4.1.cjs
|
enableGlobalCache: false
|
||||||
|
|
||||||
# uing pnp
|
|
||||||
# nodeLinker: pnp
|
|
||||||
|
|
||||||
# use these if not using PnP and have node_modules
|
|
||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
compressionLevel: 0
|
|
||||||
nmMode: hardlinks-local
|
yarnPath: .yarn/releases/yarn-4.1.1.cjs
|
||||||
enableGlobalCache: true
|
|
||||||
|
|||||||
@@ -1,79 +1,78 @@
|
|||||||
{
|
{
|
||||||
"name": "EMS-ESP",
|
"name": "EMS-ESP",
|
||||||
"version": "3.6.0",
|
"version": "3.7",
|
||||||
"description": "build EMS-ESP WebUI",
|
"description": "build EMS-ESP WebUI",
|
||||||
"homepage": "https://emsesp.github.io/docs",
|
"homepage": "https://emsesp.github.io/docs",
|
||||||
"author": "proddy",
|
"author": "proddy",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build-hosted": "vite build --mode hosted",
|
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"preview-standalone": "npm-run-all -p preview typesafe-i18n mock-api",
|
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
|
||||||
"mock-api": "nodemon --watch ../mock-api ../mock-api/server.js",
|
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"npm:mock-api\" \"vite preview\"",
|
||||||
"standalone": "npm-run-all -p dev typesafe-i18n mock-api",
|
"mock-api": "bun --watch ../mock-api/server.ts",
|
||||||
"typesafe-i18n": "typesafe-i18n",
|
"old_mock-api": "bun --watch ../mock-api/server.js",
|
||||||
|
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:mock-api\" \"vite\"",
|
||||||
|
"old_standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"npm:old_mock-api\" \"vite\"",
|
||||||
|
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||||
|
"webUI": "node progmem-generator.js",
|
||||||
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
|
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
|
||||||
"lint": "eslint . --cache --fix"
|
"lint": "eslint . --cache --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alova/adapter-xhr": "^1.0.1",
|
"@alova/adapter-xhr": "^1.0.3",
|
||||||
"@emotion/react": "^11.11.1",
|
"@babel/core": "^7.24.3",
|
||||||
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/icons-material": "^5.14.3",
|
"@mui/icons-material": "^5.15.14",
|
||||||
"@mui/material": "^5.14.4",
|
"@mui/material": "^5.15.14",
|
||||||
"@preact/compat": "^17.1.2",
|
|
||||||
"@prefresh/vite": "^2.4.1",
|
|
||||||
"@table-library/react-table-library": "4.1.7",
|
"@table-library/react-table-library": "4.1.7",
|
||||||
"@types/lodash-es": "^4.17.8",
|
"@types/imagemin": "^8.0.5",
|
||||||
"@types/node": "^20.4.9",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/react": "^18.2.20",
|
"@types/node": "^20.11.30",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react": "^18.2.72",
|
||||||
|
"@types/react-dom": "^18.2.22",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"alova": "^2.10.0",
|
"alova": "^2.18.0",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"preact": "^10.16.0",
|
|
||||||
"react": "latest",
|
"react": "latest",
|
||||||
"react-dom": "latest",
|
"react-dom": "latest",
|
||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
"react-icons": "^4.10.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-router-dom": "^6.15.0",
|
"react-router-dom": "^6.22.3",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^10.0.5",
|
||||||
"sockette": "^2.0.6",
|
"sockette": "^2.0.6",
|
||||||
"typesafe-i18n": "^5.26.0",
|
"typesafe-i18n": "^5.26.2",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.22.10",
|
"@preact/compat": "^17.1.2",
|
||||||
"@preact/preset-vite": "^2.5.0",
|
"@preact/preset-vite": "^2.8.2",
|
||||||
"@types/babel__core": "^7",
|
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
"@typescript-eslint/parser": "^7.4.0",
|
||||||
"@typescript-eslint/parser": "^6.3.0",
|
"concurrently": "^8.2.2",
|
||||||
"eslint": "^8.47.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
|
||||||
"eslint-import-resolver-typescript": "^3.6.0",
|
|
||||||
"eslint-plugin-autofix": "^1.1.0",
|
"eslint-plugin-autofix": "^1.1.0",
|
||||||
"eslint-plugin-import": "^2.28.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
"eslint-plugin-prettier": "alpha",
|
"eslint-plugin-prettier": "alpha",
|
||||||
"eslint-plugin-react": "^7.33.1",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"nodemon": "^3.0.1",
|
"preact": "^10.20.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier": "^3.0.1",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"rollup-plugin-visualizer": "^5.9.2",
|
"terser": "^5.29.2",
|
||||||
"terser": "^5.19.2",
|
"vite": "^5.2.6",
|
||||||
"vite": "^4.4.9",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-plugin-svgr": "^3.2.0",
|
"vite-tsconfig-paths": "^4.3.2"
|
||||||
"vite-tsconfig-paths": "^4.2.0"
|
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.4.1"
|
"packageManager": "yarn@4.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,32 @@
|
|||||||
const { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } = require('fs');
|
import { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } from 'fs';
|
||||||
const { resolve, relative, sep } = require('path');
|
import { resolve, relative, sep } from 'path';
|
||||||
var zlib = require('zlib');
|
import zlib from 'zlib';
|
||||||
var mime = require('mime-types');
|
import mime from 'mime-types';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
|
||||||
const INDENT = ' ';
|
const INDENT = ' ';
|
||||||
|
const outputPath = '../lib/framework/WWWData.h';
|
||||||
|
const sourcePath = './dist';
|
||||||
|
const bytesPerLine = 20;
|
||||||
|
var totalSize = 0;
|
||||||
|
|
||||||
|
const generateWWWClass = () =>
|
||||||
|
`typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
|
||||||
|
// Total size is ${totalSize} bytes
|
||||||
|
|
||||||
|
class WWWData {
|
||||||
|
${indent}public:
|
||||||
|
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||||
|
${fileInfo
|
||||||
|
.map(
|
||||||
|
(file) =>
|
||||||
|
`${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size}, "${file.hash}");`
|
||||||
|
)
|
||||||
|
.join('\n')}
|
||||||
|
${indent.repeat(2)}}
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
function getFilesSync(dir, files = []) {
|
function getFilesSync(dir, files = []) {
|
||||||
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||||
@@ -18,10 +40,6 @@ function getFilesSync(dir, files = []) {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function coherseToBuffer(input) {
|
|
||||||
// return Buffer.isBuffer(input) ? input : Buffer.from(input);
|
|
||||||
// }
|
|
||||||
|
|
||||||
function cleanAndOpen(path) {
|
function cleanAndOpen(path) {
|
||||||
if (existsSync(path)) {
|
if (existsSync(path)) {
|
||||||
unlinkSync(path);
|
unlinkSync(path);
|
||||||
@@ -29,90 +47,68 @@ function cleanAndOpen(path) {
|
|||||||
return createWriteStream(path, { flags: 'w+' });
|
return createWriteStream(path, { flags: 'w+' });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ProgmemGenerator({ outputPath = './WWWData.h', bytesPerLine = 20 }) {
|
const writeFile = (relativeFilePath, buffer) => {
|
||||||
return {
|
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
||||||
name: 'ProgmemGenerator',
|
const mimeType = mime.lookup(relativeFilePath);
|
||||||
writeBundle: () => {
|
var size = 0;
|
||||||
console.log('Generating ' + outputPath);
|
writeStream.write('const uint8_t ' + variable + '[] = {');
|
||||||
const includes = ARDUINO_INCLUDES;
|
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
||||||
const indent = INDENT;
|
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
||||||
const fileInfo = [];
|
|
||||||
const writeStream = cleanAndOpen(resolve(outputPath));
|
|
||||||
|
|
||||||
try {
|
// create sha
|
||||||
const writeIncludes = () => {
|
const hashSum = crypto.createHash('sha256');
|
||||||
writeStream.write(includes);
|
hashSum.update(zipBuffer);
|
||||||
};
|
const hash = hashSum.digest('hex');
|
||||||
|
|
||||||
const writeFile = (relativeFilePath, buffer) => {
|
zipBuffer.forEach((b) => {
|
||||||
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
if (!(size % bytesPerLine)) {
|
||||||
const mimeType = mime.lookup(relativeFilePath);
|
writeStream.write('\n');
|
||||||
var size = 0;
|
writeStream.write(indent);
|
||||||
writeStream.write('const uint8_t ' + variable + '[] = {');
|
|
||||||
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
|
||||||
const zipBuffer = zlib.gzipSync(buffer);
|
|
||||||
zipBuffer.forEach((b) => {
|
|
||||||
if (!(size % bytesPerLine)) {
|
|
||||||
writeStream.write('\n');
|
|
||||||
writeStream.write(indent);
|
|
||||||
}
|
|
||||||
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).substr(-2) + ',');
|
|
||||||
size++;
|
|
||||||
});
|
|
||||||
if (size % bytesPerLine) {
|
|
||||||
writeStream.write('\n');
|
|
||||||
}
|
|
||||||
writeStream.write('};\n\n');
|
|
||||||
fileInfo.push({
|
|
||||||
uri: '/' + relativeFilePath.replace(sep, '/'),
|
|
||||||
mimeType,
|
|
||||||
variable,
|
|
||||||
size
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeFiles = () => {
|
|
||||||
// process static files
|
|
||||||
const buildPath = resolve('build');
|
|
||||||
for (const filePath of getFilesSync(buildPath)) {
|
|
||||||
const readStream = readFileSync(filePath);
|
|
||||||
const relativeFilePath = relative(buildPath, filePath);
|
|
||||||
writeFile(relativeFilePath, readStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// process assets
|
|
||||||
// const { assets } = compilation;
|
|
||||||
// Object.keys(assets).forEach((relativeFilePath) => {
|
|
||||||
// writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateWWWClass = () =>
|
|
||||||
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
|
|
||||||
|
|
||||||
class WWWData {
|
|
||||||
${indent}public:
|
|
||||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
|
||||||
${fileInfo
|
|
||||||
.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`)
|
|
||||||
.join('\n')}
|
|
||||||
${indent.repeat(2)}}
|
|
||||||
};
|
|
||||||
`;
|
|
||||||
const writeWWWClass = () => {
|
|
||||||
writeStream.write(generateWWWClass());
|
|
||||||
};
|
|
||||||
|
|
||||||
writeIncludes();
|
|
||||||
writeFiles();
|
|
||||||
writeWWWClass();
|
|
||||||
|
|
||||||
writeStream.on('finish', () => {
|
|
||||||
// callback();
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
writeStream.end();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ',');
|
||||||
|
size++;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (size % bytesPerLine) {
|
||||||
|
writeStream.write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
writeStream.write('};\n\n');
|
||||||
|
|
||||||
|
fileInfo.push({
|
||||||
|
uri: '/' + relativeFilePath.replace(sep, '/'),
|
||||||
|
mimeType,
|
||||||
|
variable,
|
||||||
|
size,
|
||||||
|
hash
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(relativeFilePath + ' (size ' + size + ' bytes)');
|
||||||
|
totalSize += size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// start
|
||||||
|
console.log('Generating ' + outputPath + ' from ' + sourcePath);
|
||||||
|
const includes = ARDUINO_INCLUDES;
|
||||||
|
const indent = INDENT;
|
||||||
|
const fileInfo = [];
|
||||||
|
const writeStream = cleanAndOpen(resolve(outputPath));
|
||||||
|
|
||||||
|
// includes
|
||||||
|
writeStream.write(includes);
|
||||||
|
|
||||||
|
// process static files
|
||||||
|
const buildPath = resolve(sourcePath);
|
||||||
|
for (const filePath of getFilesSync(buildPath)) {
|
||||||
|
const readStream = readFileSync(filePath);
|
||||||
|
const relativeFilePath = relative(buildPath, filePath);
|
||||||
|
writeFile(relativeFilePath, readStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add class
|
||||||
|
writeStream.write(generateWWWClass());
|
||||||
|
|
||||||
|
// end
|
||||||
|
writeStream.end();
|
||||||
|
|
||||||
|
console.log('Total size: ' + totalSize / 1000 + ' KB');
|
||||||
|
|||||||
Binary file not shown.
@@ -4,7 +4,6 @@ import { ToastContainer, Slide } from 'react-toastify';
|
|||||||
import 'react-toastify/dist/ReactToastify.min.css';
|
import 'react-toastify/dist/ReactToastify.min.css';
|
||||||
|
|
||||||
import { localStorageDetector } from 'typesafe-i18n/detectors';
|
import { localStorageDetector } from 'typesafe-i18n/detectors';
|
||||||
import { FeaturesLoader } from './contexts/features';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import AppRouting from 'AppRouting';
|
import AppRouting from 'AppRouting';
|
||||||
import CustomTheme from 'CustomTheme';
|
import CustomTheme from 'CustomTheme';
|
||||||
@@ -27,11 +26,9 @@ const App: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<TypesafeI18n locale={detectedLocale}>
|
<TypesafeI18n locale={detectedLocale}>
|
||||||
<CustomTheme>
|
<CustomTheme>
|
||||||
<FeaturesLoader>
|
<AppRouting />
|
||||||
<AppRouting />
|
|
||||||
</FeaturesLoader>
|
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
position="bottom-left"
|
position="bottom-right"
|
||||||
autoClose={3000}
|
autoClose={3000}
|
||||||
hideProgressBar={false}
|
hideProgressBar={false}
|
||||||
newestOnTop={false}
|
newestOnTop={false}
|
||||||
|
|||||||
@@ -1,64 +1,55 @@
|
|||||||
|
import { useContext, type FC } from 'react';
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
import Dashboard from './project/Dashboard';
|
|
||||||
import Help from './project/Help';
|
import Help from './project/Help';
|
||||||
import Settings from './project/Settings';
|
import { Layout } from 'components';
|
||||||
import type { FC } from 'react';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
import Settings from 'framework/Settings';
|
||||||
import { Layout, RequireAdmin } from 'components';
|
|
||||||
import AccessPoint from 'framework/ap/AccessPoint';
|
import AccessPoint from 'framework/ap/AccessPoint';
|
||||||
import Mqtt from 'framework/mqtt/Mqtt';
|
import Mqtt from 'framework/mqtt/Mqtt';
|
||||||
import NetworkConnection from 'framework/network/NetworkConnection';
|
import Network from 'framework/network/Network';
|
||||||
import NetworkTime from 'framework/ntp/NetworkTime';
|
import NetworkTime from 'framework/ntp/NetworkTime';
|
||||||
|
import OTASettings from 'framework/ota/OTASettings';
|
||||||
import Security from 'framework/security/Security';
|
import Security from 'framework/security/Security';
|
||||||
|
import ESPSystemStatus from 'framework/system/ESPSystemStatus';
|
||||||
import System from 'framework/system/System';
|
import System from 'framework/system/System';
|
||||||
|
import UploadDownload from 'framework/system/UploadDownload';
|
||||||
|
import ApplicationSettings from 'project/ApplicationSettings';
|
||||||
|
import CustomEntities from 'project/CustomEntities';
|
||||||
|
import Customization from 'project/Customization';
|
||||||
|
import Devices from 'project/Devices';
|
||||||
|
import Scheduler from 'project/Scheduler';
|
||||||
|
import Sensors from 'project/Sensors';
|
||||||
|
|
||||||
const AuthenticatedRouting: FC = () => (
|
const AuthenticatedRouting: FC = () => {
|
||||||
// const location = useLocation();
|
const { me } = useContext(AuthenticatedContext);
|
||||||
// const navigate = useNavigate();
|
return (
|
||||||
// const handleApiResponseError = useCallback(
|
<Layout>
|
||||||
// (error: AxiosError) => {
|
<Routes>
|
||||||
// if (error.response && error.response.status === 401) {
|
<Route path="/devices/*" element={<Devices />} />
|
||||||
// AuthenticationApi.storeLoginRedirect(location);
|
<Route path="/sensors/*" element={<Sensors />} />
|
||||||
// navigate('/unauthorized');
|
<Route path="/system/*" element={<System />} />
|
||||||
// }
|
<Route path="/help/*" element={<Help />} />
|
||||||
// return Promise.reject(error);
|
<Route path="/*" element={<Navigate to="/" />} />
|
||||||
// },
|
{me.admin && (
|
||||||
// [location, navigate]
|
<>
|
||||||
// );
|
<Route path="/customizations/*" element={<Customization />} />
|
||||||
// useEffect(() => {
|
<Route path="/scheduler/*" element={<Scheduler />} />
|
||||||
// const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError);
|
<Route path="/customentities/*" element={<CustomEntities />} />
|
||||||
// return () => AXIOS.interceptors.response.eject(axiosHandlerId);
|
<Route path="/settings/*" element={<Settings />} />
|
||||||
// }, [handleApiResponseError]);
|
<Route path="/settings/network/*" element={<Network />} />
|
||||||
|
<Route path="/settings/ems-esp/*" element={<ApplicationSettings />} />
|
||||||
<Layout>
|
<Route path="/settings/ap/*" element={<AccessPoint />} />
|
||||||
<Routes>
|
<Route path="/settings/ntp/*" element={<NetworkTime />} />
|
||||||
<Route path="/dashboard/*" element={<Dashboard />} />
|
<Route path="/settings/mqtt/*" element={<Mqtt />} />
|
||||||
<Route
|
<Route path="/settings/ota/*" element={<OTASettings />} />
|
||||||
path="/settings/*"
|
<Route path="/settings/security/*" element={<Security />} />
|
||||||
element={
|
<Route path="/settings/espsystemstatus/*" element={<ESPSystemStatus />} />
|
||||||
<RequireAdmin>
|
<Route path="/settings/upload/*" element={<UploadDownload />} />
|
||||||
<Settings />
|
</>
|
||||||
</RequireAdmin>
|
)}
|
||||||
}
|
</Routes>
|
||||||
/>
|
</Layout>
|
||||||
<Route path="/help/*" element={<Help />} />
|
);
|
||||||
|
};
|
||||||
<Route path="/network/*" element={<NetworkConnection />} />
|
|
||||||
<Route path="/ap/*" element={<AccessPoint />} />
|
|
||||||
<Route path="/ntp/*" element={<NetworkTime />} />
|
|
||||||
<Route path="/mqtt/*" element={<Mqtt />} />
|
|
||||||
<Route
|
|
||||||
path="/security/*"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<Security />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/system/*" element={<System />} />
|
|
||||||
<Route path="/*" element={<Navigate to="/" />} />
|
|
||||||
</Routes>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default AuthenticatedRouting;
|
export default AuthenticatedRouting;
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ const theme = responsiveFontSizes(
|
|||||||
},
|
},
|
||||||
info: {
|
info: {
|
||||||
main: '#607d8b' // blueGrey[500]
|
main: '#607d8b' // blueGrey[500]
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
disabled: '#eee' // white
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Box, Paper, Typography, MenuItem, TextField, Button } from '@mui/materi
|
|||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { FeaturesContext } from './contexts/features';
|
|
||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
import type { Locales } from 'i18n/i18n-types';
|
||||||
@@ -15,15 +14,16 @@ import { PROJECT_NAME } from 'api/env';
|
|||||||
import { ValidatedPasswordField, ValidatedTextField } from 'components';
|
import { ValidatedPasswordField, ValidatedTextField } from 'components';
|
||||||
import { AuthenticationContext } from 'contexts/authentication';
|
import { AuthenticationContext } from 'contexts/authentication';
|
||||||
|
|
||||||
import { ReactComponent as DEflag } from 'i18n/DE.svg';
|
import DEflag from 'i18n/DE.svg';
|
||||||
import { ReactComponent as FRflag } from 'i18n/FR.svg';
|
import FRflag from 'i18n/FR.svg';
|
||||||
import { ReactComponent as GBflag } from 'i18n/GB.svg';
|
import GBflag from 'i18n/GB.svg';
|
||||||
import { ReactComponent as ITflag } from 'i18n/IT.svg';
|
import ITflag from 'i18n/IT.svg';
|
||||||
import { ReactComponent as NLflag } from 'i18n/NL.svg';
|
import NLflag from 'i18n/NL.svg';
|
||||||
import { ReactComponent as NOflag } from 'i18n/NO.svg';
|
import NOflag from 'i18n/NO.svg';
|
||||||
import { ReactComponent as PLflag } from 'i18n/PL.svg';
|
import PLflag from 'i18n/PL.svg';
|
||||||
import { ReactComponent as SVflag } from 'i18n/SV.svg';
|
import SKflag from 'i18n/SK.svg';
|
||||||
import { ReactComponent as TRflag } from 'i18n/TR.svg';
|
import SVflag from 'i18n/SV.svg';
|
||||||
|
import TRflag from 'i18n/TR.svg';
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
import { onEnterCallback, updateValue } from 'utils';
|
import { onEnterCallback, updateValue } from 'utils';
|
||||||
@@ -34,8 +34,6 @@ const SignIn: FC = () => {
|
|||||||
|
|
||||||
const { LL, setLocale, locale } = useContext(I18nContext);
|
const { LL, setLocale, locale } = useContext(I18nContext);
|
||||||
|
|
||||||
const { features } = useContext(FeaturesContext);
|
|
||||||
|
|
||||||
const [signInRequest, setSignInRequest] = useState<SignInRequest>({
|
const [signInRequest, setSignInRequest] = useState<SignInRequest>({
|
||||||
username: '',
|
username: '',
|
||||||
password: ''
|
password: ''
|
||||||
@@ -111,43 +109,46 @@ const SignIn: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Typography variant="h4">{PROJECT_NAME}</Typography>
|
<Typography variant="h4">{PROJECT_NAME}</Typography>
|
||||||
<Typography variant="subtitle2">{features.version}</Typography>
|
|
||||||
|
|
||||||
<TextField name="locale" variant="outlined" value={locale} onChange={onLocaleSelected} size="small" select>
|
<TextField name="locale" variant="outlined" value={locale} onChange={onLocaleSelected} size="small" select>
|
||||||
<MenuItem key="de" value="de">
|
<MenuItem key="de" value="de">
|
||||||
<DEflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
DE
|
DE
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="en" value="en">
|
<MenuItem key="en" value="en">
|
||||||
<GBflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
EN
|
EN
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="fr" value="fr">
|
<MenuItem key="fr" value="fr">
|
||||||
<FRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
FR
|
FR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="it" value="it">
|
<MenuItem key="it" value="it">
|
||||||
<ITflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
IT
|
IT
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="nl" value="nl">
|
<MenuItem key="nl" value="nl">
|
||||||
<NLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NL
|
NL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="no" value="no">
|
<MenuItem key="no" value="no">
|
||||||
<NOflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
NO
|
NO
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="pl" value="pl">
|
<MenuItem key="pl" value="pl">
|
||||||
<PLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
PL
|
PL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem key="sk" value="sk">
|
||||||
|
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SK
|
||||||
|
</MenuItem>
|
||||||
<MenuItem key="sv" value="sv">
|
<MenuItem key="sv" value="sv">
|
||||||
<SVflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
SV
|
SV
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem key="tr" value="tr">
|
<MenuItem key="tr" value="tr">
|
||||||
<TRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
TR
|
TR
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import jwtDecode from 'jwt-decode';
|
import { jwtDecode } from 'jwt-decode';
|
||||||
import { ACCESS_TOKEN, alovaInstance } from './endpoints';
|
import { ACCESS_TOKEN, alovaInstance } from './endpoints';
|
||||||
import type * as H from 'history';
|
import type * as H from 'history';
|
||||||
import type { Path } from 'react-router-dom';
|
import type { Path } from 'react-router-dom';
|
||||||
@@ -32,7 +32,7 @@ export function fetchLoginRedirect(): Partial<Path> {
|
|||||||
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH);
|
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH);
|
||||||
clearLoginRedirect();
|
clearLoginRedirect();
|
||||||
return {
|
return {
|
||||||
pathname: signInPathname || `/dashboard`,
|
pathname: signInPathname || `/devices`,
|
||||||
search: (signInPathname && signInSearch) || undefined
|
search: (signInPathname && signInSearch) || undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { alovaInstance } from './endpoints';
|
|
||||||
|
|
||||||
import type { Features } from 'types';
|
|
||||||
|
|
||||||
export const readFeatures = () => alovaInstance.Get<Features>('/rest/features');
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { alovaInstance } from './endpoints';
|
import { alovaInstance } from './endpoints';
|
||||||
import type { MqttSettings, MqttStatus } from 'types';
|
import type { MqttSettingsType, MqttStatusType } from 'types';
|
||||||
|
|
||||||
export const readMqttStatus = () => alovaInstance.Get<MqttStatus>('/rest/mqttStatus');
|
export const readMqttStatus = () => alovaInstance.Get<MqttStatusType>('/rest/mqttStatus');
|
||||||
export const readMqttSettings = () => alovaInstance.Get<MqttSettings>('/rest/mqttSettings');
|
export const readMqttSettings = () => alovaInstance.Get<MqttSettingsType>('/rest/mqttSettings');
|
||||||
export const updateMqttSettings = (data: MqttSettings) => alovaInstance.Post<MqttSettings>('/rest/mqttSettings', data);
|
export const updateMqttSettings = (data: MqttSettingsType) =>
|
||||||
|
alovaInstance.Post<MqttSettingsType>('/rest/mqttSettings', data);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { alovaInstance, alovaInstanceGH } from './endpoints';
|
import { alovaInstance, alovaInstanceGH } from './endpoints';
|
||||||
import type { OTASettings, SystemStatus, LogSettings } from 'types';
|
import type { OTASettings, SystemStatus, LogSettings, ESPSystemStatus } from 'types';
|
||||||
|
|
||||||
// SystemStatus - also used to ping in Restart monitor for pinging
|
// ESPSystemStatus - also used to ping in Restart monitor for pinging
|
||||||
|
export const readESPSystemStatus = () => alovaInstance.Get<ESPSystemStatus>('/rest/ESPSystemStatus');
|
||||||
|
|
||||||
|
// SystemStatus
|
||||||
export const readSystemStatus = () => alovaInstance.Get<SystemStatus>('/rest/systemStatus');
|
export const readSystemStatus = () => alovaInstance.Get<SystemStatus>('/rest/systemStatus');
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
|
|||||||
@@ -498,8 +498,8 @@ function createStructureReader(structure, firstId) {
|
|||||||
key === '__proto__'
|
key === '__proto__'
|
||||||
? '__proto_:r()'
|
? '__proto_:r()'
|
||||||
: validName.test(key)
|
: validName.test(key)
|
||||||
? key + ':r()'
|
? key + ':r()'
|
||||||
: '[' + JSON.stringify(key) + ']:r()'
|
: '[' + JSON.stringify(key) + ']:r()'
|
||||||
)
|
)
|
||||||
.join(',') +
|
.join(',') +
|
||||||
'})}'
|
'})}'
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import type { FC } from 'react';
|
|||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
|
|
||||||
interface SectionContentProps extends RequiredChildrenProps {
|
interface SectionContentProps extends RequiredChildrenProps {
|
||||||
title: string;
|
title?: string;
|
||||||
titleGutter?: boolean;
|
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,7 +12,9 @@ const SectionContent: FC<SectionContentProps> = (props) => {
|
|||||||
const { children, title, id } = props;
|
const { children, title, id } = props;
|
||||||
return (
|
return (
|
||||||
<Paper id={id} sx={{ p: 2, m: 2 }}>
|
<Paper id={id} sx={{ p: 2, m: 2 }}>
|
||||||
<Divider sx={{ pb: 2, borderColor: 'primary.main', fontSize: 20, color: 'primary.main' }}>{title}</Divider>
|
{title && (
|
||||||
|
<Divider sx={{ pb: 2, borderColor: 'primary.main', fontSize: 20, color: 'primary.main' }}>{title}</Divider>
|
||||||
|
)}
|
||||||
{children}
|
{children}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import { AppBar, Box, IconButton, Toolbar, Typography } from '@mui/material';
|
import { AppBar, IconButton, Toolbar, Typography } from '@mui/material';
|
||||||
import LayoutAuthMenu from './LayoutAuthMenu';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
export const DRAWER_WIDTH = 210;
|
export const DRAWER_WIDTH = 210;
|
||||||
@@ -27,8 +26,6 @@ const LayoutAppBar: FC<LayoutAppBarProps> = ({ title, onToggleDrawer }) => (
|
|||||||
<Typography variant="h6" noWrap component="div">
|
<Typography variant="h6" noWrap component="div">
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box flexGrow={1} />
|
|
||||||
<LayoutAuthMenu />
|
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
|
||||||
import PersonIcon from '@mui/icons-material/Person';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Divider,
|
|
||||||
IconButton,
|
|
||||||
Popover,
|
|
||||||
Typography,
|
|
||||||
Avatar,
|
|
||||||
styled,
|
|
||||||
MenuItem,
|
|
||||||
TextField
|
|
||||||
} from '@mui/material';
|
|
||||||
import { useState, useContext } from 'react';
|
|
||||||
import type { TypographyProps } from '@mui/material';
|
|
||||||
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
|
||||||
import type { FC, ChangeEventHandler } from 'react';
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { ReactComponent as DEflag } from 'i18n/DE.svg';
|
|
||||||
import { ReactComponent as FRflag } from 'i18n/FR.svg';
|
|
||||||
import { ReactComponent as GBflag } from 'i18n/GB.svg';
|
|
||||||
import { ReactComponent as ITflag } from 'i18n/IT.svg';
|
|
||||||
import { ReactComponent as NLflag } from 'i18n/NL.svg';
|
|
||||||
import { ReactComponent as NOflag } from 'i18n/NO.svg';
|
|
||||||
import { ReactComponent as PLflag } from 'i18n/PL.svg';
|
|
||||||
import { ReactComponent as SVflag } from 'i18n/SV.svg';
|
|
||||||
import { ReactComponent as TRflag } from 'i18n/TR.svg';
|
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
|
||||||
|
|
||||||
const ItemTypography = styled(Typography)<TypographyProps>({
|
|
||||||
maxWidth: '250px',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis'
|
|
||||||
});
|
|
||||||
|
|
||||||
const LayoutAuthMenu: FC = () => {
|
|
||||||
const { me, signOut } = useContext(AuthenticatedContext);
|
|
||||||
|
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
setAnchorEl(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { locale, LL, setLocale } = useContext(I18nContext);
|
|
||||||
|
|
||||||
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({ target }) => {
|
|
||||||
const loc = target.value as Locales;
|
|
||||||
localStorage.setItem('lang', loc);
|
|
||||||
await loadLocaleAsync(loc);
|
|
||||||
setLocale(loc);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setAnchorEl(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const open = Boolean(anchorEl);
|
|
||||||
const id = anchorEl ? 'app-menu-popover' : undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
name="locale"
|
|
||||||
InputProps={{ style: { fontSize: 10 } }}
|
|
||||||
variant="outlined"
|
|
||||||
value={locale}
|
|
||||||
onChange={onLocaleSelected}
|
|
||||||
size="small"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem key="de" value="de">
|
|
||||||
<DEflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
DE
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="en" value="en">
|
|
||||||
<GBflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
EN
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="fr" value="fr">
|
|
||||||
<FRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
FR
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="it" value="it">
|
|
||||||
<ITflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
IT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="nl" value="nl">
|
|
||||||
<NLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="no" value="no">
|
|
||||||
<NOflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NO
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="pl" value="pl">
|
|
||||||
<PLflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
PL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
|
||||||
<SVflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SV
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="tr" value="tr">
|
|
||||||
<TRflag style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
TR
|
|
||||||
</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
id="open-auth-menu"
|
|
||||||
sx={{ ml: 1, padding: 0 }}
|
|
||||||
aria-describedby={id}
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<AccountCircleIcon />
|
|
||||||
</IconButton>
|
|
||||||
<Popover
|
|
||||||
id="app-menu-popover"
|
|
||||||
sx={{ mt: 1 }}
|
|
||||||
open={open}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
onClose={handleClose}
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'bottom',
|
|
||||||
horizontal: 'center'
|
|
||||||
}}
|
|
||||||
transformOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box display="flex" flexDirection="row" alignItems="center" p={2}>
|
|
||||||
<Avatar sx={{ width: 80, height: 80 }}>
|
|
||||||
<PersonIcon fontSize="large" />
|
|
||||||
</Avatar>
|
|
||||||
<Box pl={2}>
|
|
||||||
<ItemTypography variant="h6">{me.username}</ItemTypography>
|
|
||||||
<ItemTypography variant="body1">
|
|
||||||
{me.admin ? LL.ADMIN() : LL.GUEST()} {LL.USER(2)}
|
|
||||||
</ItemTypography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Divider />
|
|
||||||
<Box p={1.5}>
|
|
||||||
<Button variant="outlined" fullWidth color="primary" onClick={() => signOut(true)}>
|
|
||||||
{LL.SIGN_OUT()}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Popover>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LayoutAuthMenu;
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Box, Divider, Drawer, Toolbar, Typography, styled } from '@mui/material';
|
import { Box, Divider, Drawer, Toolbar, Typography, styled } from '@mui/material';
|
||||||
import { DRAWER_WIDTH } from './Layout';
|
import { DRAWER_WIDTH } from './Layout';
|
||||||
|
|
||||||
import LayoutMenu from './LayoutMenu';
|
import LayoutMenu from './LayoutMenu';
|
||||||
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { PROJECT_NAME } from 'api/env';
|
import { PROJECT_NAME } from 'api/env';
|
||||||
|
|||||||
@@ -1,53 +1,254 @@
|
|||||||
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||||
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||||
import DashboardIcon from '@mui/icons-material/Dashboard';
|
import CategoryIcon from '@mui/icons-material/Category';
|
||||||
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
import InfoIcon from '@mui/icons-material/Info';
|
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LiveHelpIcon from '@mui/icons-material/LiveHelp';
|
||||||
|
import MoreTimeIcon from '@mui/icons-material/MoreTime';
|
||||||
|
import PersonIcon from '@mui/icons-material/Person';
|
||||||
|
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
|
||||||
|
import SensorsIcon from '@mui/icons-material/Sensors';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
|
|
||||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
|
||||||
import TuneIcon from '@mui/icons-material/Tune';
|
|
||||||
import { Divider, List } from '@mui/material';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
|
import {
|
||||||
|
Divider,
|
||||||
|
List,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Popover,
|
||||||
|
Avatar,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
ListItem,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { useContext, useState } from 'react';
|
||||||
|
import type { Locales } from 'i18n/i18n-types';
|
||||||
|
import type { FC, ChangeEventHandler } from 'react';
|
||||||
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
||||||
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import DEflag from 'i18n/DE.svg';
|
||||||
|
import FRflag from 'i18n/FR.svg';
|
||||||
|
import GBflag from 'i18n/GB.svg';
|
||||||
|
import ITflag from 'i18n/IT.svg';
|
||||||
|
import NLflag from 'i18n/NL.svg';
|
||||||
|
import NOflag from 'i18n/NO.svg';
|
||||||
|
import PLflag from 'i18n/PL.svg';
|
||||||
|
import SKflag from 'i18n/SK.svg';
|
||||||
|
import SVflag from 'i18n/SV.svg';
|
||||||
|
import TRflag from 'i18n/TR.svg';
|
||||||
|
|
||||||
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
|
|
||||||
const LayoutMenu: FC = () => {
|
const LayoutMenu: FC = () => {
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
const { me, signOut } = useContext(AuthenticatedContext);
|
||||||
const { LL } = useI18nContext();
|
const { locale, LL, setLocale } = useContext(I18nContext);
|
||||||
|
|
||||||
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const id = anchorEl ? 'app-menu-popover' : undefined;
|
||||||
|
|
||||||
|
const [menuOpen, setMenuOpen] = useState(true);
|
||||||
|
|
||||||
|
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({ target }) => {
|
||||||
|
const loc = target.value as Locales;
|
||||||
|
localStorage.setItem('lang', loc);
|
||||||
|
await loadLocaleAsync(loc);
|
||||||
|
setLocale(loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClick = (event: any) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List disablePadding component="nav">
|
<List component="nav">
|
||||||
<LayoutMenuItem icon={DashboardIcon} label={LL.DASHBOARD()} to={`/dashboard`} />
|
<LayoutMenuItem icon={CategoryIcon} label={LL.DEVICES()} to={`/devices`} />
|
||||||
<LayoutMenuItem
|
<LayoutMenuItem icon={SensorsIcon} label={LL.SENSORS()} to={`/sensors`} />
|
||||||
icon={TuneIcon}
|
|
||||||
label={LL.SETTINGS_OF('')}
|
|
||||||
to={`/settings`}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
<LayoutMenuItem icon={InfoIcon} label={LL.HELP_OF('')} to={`/help`} />
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
bgcolor: menuOpen ? 'rgba(71, 98, 130, 0.2)' : null,
|
||||||
|
pb: menuOpen ? 2 : 0
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemButton
|
||||||
|
alignItems="flex-start"
|
||||||
|
onClick={() => setMenuOpen(!menuOpen)}
|
||||||
|
sx={{
|
||||||
|
pt: 2.5,
|
||||||
|
pb: menuOpen ? 0 : 2.5,
|
||||||
|
'&:hover, &:focus': { '& svg': { opacity: 1 } }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemText
|
||||||
|
// TODO: translate
|
||||||
|
primary="Customize"
|
||||||
|
primaryTypographyProps={{
|
||||||
|
fontWeight: '600',
|
||||||
|
mb: '2px',
|
||||||
|
color: 'lightblue'
|
||||||
|
}}
|
||||||
|
// TODO: translate
|
||||||
|
secondary="Customizations, Scheduler and Custom Entities"
|
||||||
|
secondaryTypographyProps={{
|
||||||
|
noWrap: true,
|
||||||
|
fontSize: 12,
|
||||||
|
color: menuOpen ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0.5)'
|
||||||
|
}}
|
||||||
|
sx={{ my: 0 }}
|
||||||
|
/>
|
||||||
|
<KeyboardArrowDown
|
||||||
|
sx={{
|
||||||
|
mr: -1,
|
||||||
|
opacity: 0,
|
||||||
|
transform: menuOpen ? 'rotate(-180deg)' : 'rotate(0)',
|
||||||
|
transition: '0.2s'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
{menuOpen && (
|
||||||
|
<>
|
||||||
|
<LayoutMenuItem
|
||||||
|
icon={ConstructionIcon}
|
||||||
|
label={LL.CUSTOMIZATIONS()}
|
||||||
|
disabled={!me.admin}
|
||||||
|
to={`/customizations`}
|
||||||
|
/>
|
||||||
|
<LayoutMenuItem icon={MoreTimeIcon} label={LL.SCHEDULER()} disabled={!me.admin} to={`/scheduler`} />
|
||||||
|
<LayoutMenuItem
|
||||||
|
icon={PlaylistAddIcon}
|
||||||
|
label={LL.CUSTOM_ENTITIES(0)}
|
||||||
|
disabled={!me.admin}
|
||||||
|
to={`/customentities`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</List>
|
</List>
|
||||||
<List disablePadding component="nav">
|
|
||||||
<LayoutMenuItem icon={SettingsEthernetIcon} label={LL.NETWORK(0)} to="/network" />
|
<List style={{ marginTop: `auto` }}>
|
||||||
<LayoutMenuItem icon={SettingsInputAntennaIcon} label={LL.ACCESS_POINT(0)} to="/ap" />
|
<LayoutMenuItem icon={AssessmentIcon} label={LL.SYSTEM(0)} to="/system" />
|
||||||
<LayoutMenuItem icon={AccessTimeIcon} label="NTP" to="/ntp" />
|
<LayoutMenuItem icon={SettingsIcon} label={LL.SETTINGS(0)} disabled={!me.admin} to="/settings" />
|
||||||
<LayoutMenuItem icon={DeviceHubIcon} label="MQTT" to="/mqtt" />
|
<LayoutMenuItem icon={LiveHelpIcon} label={LL.HELP_OF('')} to={`/help`} />
|
||||||
<LayoutMenuItem
|
|
||||||
icon={LockIcon}
|
|
||||||
label={LL.SECURITY(0)}
|
|
||||||
to="/security"
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
<LayoutMenuItem icon={SettingsIcon} label={LL.SYSTEM(0)} to="/system" />
|
|
||||||
</List>
|
</List>
|
||||||
|
<Divider />
|
||||||
|
<List>
|
||||||
|
<ListItem disablePadding onClick={handleClick}>
|
||||||
|
<ListItemButton>
|
||||||
|
<ListItemIcon>
|
||||||
|
<AccountCircleIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{me.username}</ListItemText>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Popover
|
||||||
|
id={id}
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
p={2}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
border: '2px solid grey'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
<ListItem disablePadding>
|
||||||
|
<Avatar sx={{ bgcolor: '#b1395f', color: 'white' }}>
|
||||||
|
<PersonIcon />
|
||||||
|
</Avatar>
|
||||||
|
<ListItemText
|
||||||
|
sx={{ pl: 2 }}
|
||||||
|
primary={me.username}
|
||||||
|
secondary={(me.admin ? LL.ADMIN() : LL.GUEST()) + ' Account'}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
<Box p={2}>
|
||||||
|
<TextField
|
||||||
|
name="locale"
|
||||||
|
InputProps={{ style: { fontSize: 10 } }}
|
||||||
|
variant="outlined"
|
||||||
|
value={locale}
|
||||||
|
onChange={onLocaleSelected}
|
||||||
|
size="small"
|
||||||
|
select
|
||||||
|
>
|
||||||
|
<MenuItem key="de" value="de">
|
||||||
|
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
DE
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="en" value="en">
|
||||||
|
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
EN
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="fr" value="fr">
|
||||||
|
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
FR
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="it" value="it">
|
||||||
|
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
IT
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="nl" value="nl">
|
||||||
|
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="no" value="no">
|
||||||
|
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NO
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="pl" value="pl">
|
||||||
|
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
PL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sk" value="sk">
|
||||||
|
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SK
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sv" value="sv">
|
||||||
|
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SV
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="tr" value="tr">
|
||||||
|
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
TR
|
||||||
|
</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button variant="outlined" fullWidth color="primary" onClick={() => signOut(true)}>
|
||||||
|
{LL.SIGN_OUT()}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Popover>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import type { SvgIconProps } from '@mui/material';
|
import type { SvgIconProps } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -18,14 +18,12 @@ const LayoutMenuItem: FC<LayoutMenuItemProps> = ({ icon: Icon, label, to, disabl
|
|||||||
const selected = routeMatches(to, pathname);
|
const selected = routeMatches(to, pathname);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem disablePadding>
|
<ListItemButton component={Link} to={to} disabled={disabled} selected={selected}>
|
||||||
<ListItemButton component={Link} to={to} disabled={disabled} selected={selected}>
|
<ListItemIcon sx={{ color: selected ? '#90caf9' : '#9e9e9e' }}>
|
||||||
<ListItemIcon sx={{ color: selected ? '#90caf9' : '#9e9e9e' }}>
|
<Icon />
|
||||||
<Icon />
|
</ListItemIcon>
|
||||||
</ListItemIcon>
|
<ListItemText sx={{ color: selected ? '#90caf9' : '#f5f5f5' }}>{label}</ListItemText>
|
||||||
<ListItemText sx={{ color: selected ? '#90caf9' : '#f5f5f5' }}>{label}</ListItemText>
|
</ListItemButton>
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
52
interface/src/components/layout/ListMenuItem.tsx
Normal file
52
interface/src/components/layout/ListMenuItem.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
|
||||||
|
import { Avatar, ListItem, ListItemAvatar, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import type { SvgIconProps } from '@mui/material';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
interface ListMenuItemProps {
|
||||||
|
icon: React.ComponentType<SvgIconProps>;
|
||||||
|
bgcolor?: string;
|
||||||
|
label: string;
|
||||||
|
text: string;
|
||||||
|
to?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function RenderIcon({ icon: Icon, bgcolor, label, text }: ListMenuItemProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor, color: 'white' }}>
|
||||||
|
<Icon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={label} secondary={text} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LayoutMenuItem: FC<ListMenuItemProps> = ({ icon, bgcolor, label, text, to, disabled }) => (
|
||||||
|
<>
|
||||||
|
{to && !disabled ? (
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to={to}>
|
||||||
|
<RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} to="" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
) : (
|
||||||
|
<ListItem>
|
||||||
|
<RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} to="" />
|
||||||
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default LayoutMenuItem;
|
||||||
@@ -14,7 +14,7 @@ const RouterTabs: FC<RouterTabsProps> = ({ value, children }) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
|
const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
const handleTabChange = (event: React.ChangeEvent<HTMLInputElement>, path: string) => {
|
const handleTabChange = (_event: any, path: string) => {
|
||||||
navigate(path);
|
navigate(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useMatch, useResolvedPath } from 'react-router-dom';
|
import { useMatch, useResolvedPath } from 'react-router-dom';
|
||||||
|
|
||||||
export const useRouterTab = () => {
|
export const useRouterTab = () => {
|
||||||
const routerTabPath = useResolvedPath(':tab');
|
const routerTabPathMatch = useMatch(useResolvedPath(':tab').pathname);
|
||||||
const routerTabPathMatch = useMatch(routerTabPath.pathname);
|
|
||||||
|
|
||||||
const routerTab = routerTabPathMatch?.params?.tab || false;
|
const routerTab = routerTabPathMatch?.params?.tab || false;
|
||||||
|
|
||||||
return { routerTab } as const;
|
return { routerTab } as const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,8 +50,10 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
|
|||||||
|
|
||||||
const progressText = () => {
|
const progressText = () => {
|
||||||
if (uploading) {
|
if (uploading) {
|
||||||
if (progress.total) {
|
if (progress.total && progress.loaded) {
|
||||||
return LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%';
|
return progress.loaded <= progress.total
|
||||||
|
? LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%'
|
||||||
|
: LL.UPLOADING() + ': ' + Math.round((progress.total * 100) / progress.loaded) + '%';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LL.UPLOAD_DROP_TEXT();
|
return LL.UPLOAD_DROP_TEXT();
|
||||||
@@ -61,7 +63,7 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
|
|||||||
<Box
|
<Box
|
||||||
{...getRootProps({
|
{...getRootProps({
|
||||||
sx: {
|
sx: {
|
||||||
py: 8,
|
py: 4,
|
||||||
px: 2,
|
px: 2,
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
@@ -83,7 +85,13 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
|
|||||||
<Box width="100%" p={2}>
|
<Box width="100%" p={2}>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
value={progress.total === 0 ? 0 : Math.round((progress.loaded * 100) / progress.total)}
|
value={
|
||||||
|
progress.total === 0 || progress.loaded === 0
|
||||||
|
? 0
|
||||||
|
: progress.loaded <= progress.total
|
||||||
|
? Math.round((progress.loaded * 100) / progress.total)
|
||||||
|
: Math.round((progress.total * 100) / progress.loaded)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}>
|
<Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { redirect } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { AuthenticationContext } from './context';
|
import { AuthenticationContext } from './context';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -15,8 +15,6 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const [initialized, setInitialized] = useState<boolean>(false);
|
const [initialized, setInitialized] = useState<boolean>(false);
|
||||||
const [me, setMe] = useState<Me>();
|
const [me, setMe] = useState<Me>();
|
||||||
|
|
||||||
@@ -36,11 +34,12 @@ const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const signOut = (redirect: boolean) => {
|
const signOut = (doRedirect: boolean) => {
|
||||||
AuthenticationApi.clearAccessToken();
|
AuthenticationApi.clearAccessToken();
|
||||||
setMe(undefined);
|
setMe(undefined);
|
||||||
if (redirect) {
|
if (doRedirect) {
|
||||||
navigate('/');
|
// navigate('/');
|
||||||
|
redirect('/');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import { useRequest } from 'alova';
|
|
||||||
|
|
||||||
import { FeaturesContext } from '.';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
import type { RequiredChildrenProps } from 'utils';
|
|
||||||
import * as FeaturesApi from 'api/features';
|
|
||||||
|
|
||||||
const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
|
|
||||||
const { data: features } = useRequest(FeaturesApi.readFeatures);
|
|
||||||
|
|
||||||
if (features) {
|
|
||||||
return (
|
|
||||||
<FeaturesContext.Provider
|
|
||||||
value={{
|
|
||||||
features
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</FeaturesContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FeaturesLoader;
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
|
|
||||||
import type { Features } from 'types';
|
|
||||||
|
|
||||||
export interface FeaturesContextValue {
|
|
||||||
features: Features;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FeaturesContextDefaultValue = {} as FeaturesContextValue;
|
|
||||||
export const FeaturesContext = createContext(FeaturesContextDefaultValue);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from './context';
|
|
||||||
export { default as FeaturesLoader } from './FeaturesLoader';
|
|
||||||
250
interface/src/framework/Settings.tsx
Normal file
250
interface/src/framework/Settings.tsx
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CastIcon from '@mui/icons-material/Cast';
|
||||||
|
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||||
|
import ImportExportIcon from '@mui/icons-material/ImportExport';
|
||||||
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
|
import MemoryIcon from '@mui/icons-material/Memory';
|
||||||
|
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||||
|
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
|
||||||
|
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
|
||||||
|
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||||
|
import TuneIcon from '@mui/icons-material/Tune';
|
||||||
|
|
||||||
|
import { List, Button, Dialog, DialogActions, DialogContent, DialogTitle, Box } from '@mui/material';
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import { useState, type FC } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import RestartMonitor from './system/RestartMonitor';
|
||||||
|
import { dialogStyle } from 'CustomTheme';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
|
import { ButtonRow, SectionContent, useLayoutTitle } from 'components';
|
||||||
|
import ListMenuItem from 'components/layout/ListMenuItem';
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
|
const Settings: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
useLayoutTitle(LL.SETTINGS(0));
|
||||||
|
|
||||||
|
const [confirmRestart, setConfirmRestart] = useState<boolean>(false);
|
||||||
|
const [confirmFactoryReset, setConfirmFactoryReset] = useState<boolean>(false);
|
||||||
|
const [processing, setProcessing] = useState<boolean>(false);
|
||||||
|
const [restarting, setRestarting] = useState<boolean>();
|
||||||
|
|
||||||
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { send: factoryResetCommand } = useRequest(SystemApi.factoryReset(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { send: partitionCommand } = useRequest(SystemApi.partition(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const restart = async () => {
|
||||||
|
setProcessing(true);
|
||||||
|
await restartCommand()
|
||||||
|
.then(() => {
|
||||||
|
setRestarting(true);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setConfirmRestart(false);
|
||||||
|
setProcessing(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const factoryReset = async () => {
|
||||||
|
setProcessing(true);
|
||||||
|
await factoryResetCommand()
|
||||||
|
.then(() => {
|
||||||
|
setRestarting(true);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setConfirmFactoryReset(false);
|
||||||
|
setProcessing(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const partition = async () => {
|
||||||
|
setProcessing(true);
|
||||||
|
await partitionCommand()
|
||||||
|
.then(() => {
|
||||||
|
setRestarting(true);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setConfirmRestart(false);
|
||||||
|
setProcessing(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderRestartDialog = () => (
|
||||||
|
<Dialog sx={dialogStyle} open={confirmRestart} onClose={() => setConfirmRestart(false)}>
|
||||||
|
<DialogTitle>{LL.RESTART()}</DialogTitle>
|
||||||
|
<DialogContent dividers>{LL.RESTART_CONFIRM()}</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
startIcon={<CancelIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setConfirmRestart(false)}
|
||||||
|
disabled={processing}
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<PowerSettingsNewIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={restart}
|
||||||
|
disabled={processing}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{LL.RESTART()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<PowerSettingsNewIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={partition}
|
||||||
|
disabled={processing}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
EMS-ESP Loader
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderFactoryResetDialog = () => (
|
||||||
|
<Dialog sx={dialogStyle} open={confirmFactoryReset} onClose={() => setConfirmFactoryReset(false)}>
|
||||||
|
<DialogTitle>{LL.FACTORY_RESET()}</DialogTitle>
|
||||||
|
<DialogContent dividers>{LL.SYSTEM_FACTORY_TEXT_DIALOG()}</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
startIcon={<CancelIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setConfirmFactoryReset(false)}
|
||||||
|
disabled={processing}
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<SettingsBackupRestoreIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={factoryReset}
|
||||||
|
disabled={processing}
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
{LL.FACTORY_RESET()}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
|
const content = () => (
|
||||||
|
<>
|
||||||
|
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
||||||
|
{/* TODO: translate */}
|
||||||
|
<ListMenuItem
|
||||||
|
icon={TuneIcon}
|
||||||
|
bgcolor="#134ba2"
|
||||||
|
label={LL.APPLICATION_SETTINGS()}
|
||||||
|
text="Modify EMS-ESP Application Settings"
|
||||||
|
to="ems-esp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
icon={SettingsEthernetIcon}
|
||||||
|
bgcolor="#40828f"
|
||||||
|
label={LL.NETWORK(0)}
|
||||||
|
text={LL.CONFIGURE(LL.SETTINGS_OF(LL.NETWORK(0)))}
|
||||||
|
to="network"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
icon={SettingsInputAntennaIcon}
|
||||||
|
bgcolor="#5f9a5f"
|
||||||
|
label={LL.ACCESS_POINT(0)}
|
||||||
|
text={LL.CONFIGURE(LL.ACCESS_POINT(0))}
|
||||||
|
to="ap"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
icon={AccessTimeIcon}
|
||||||
|
bgcolor="#c5572c"
|
||||||
|
label="NTP"
|
||||||
|
text={LL.CONFIGURE(LL.LOCAL_TIME())}
|
||||||
|
to="ntp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListMenuItem icon={DeviceHubIcon} bgcolor="#68374d" label="MQTT" text={LL.CONFIGURE('MQTT')} to="mqtt" />
|
||||||
|
|
||||||
|
<ListMenuItem icon={CastIcon} bgcolor="#efc34b" label="OTA" text={LL.CONFIGURE('OTA')} to="ota" />
|
||||||
|
|
||||||
|
{/* TODO: translate */}
|
||||||
|
<ListMenuItem icon={LockIcon} label={LL.SECURITY(0)} text="Add/Remove Users" to="security" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
icon={MemoryIcon}
|
||||||
|
bgcolor="#b1395f"
|
||||||
|
label={LL.STATUS_OF('ESP32')}
|
||||||
|
text="ESP32 Information"
|
||||||
|
to="espsystemstatus"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* TODO: translate */}
|
||||||
|
<ListMenuItem
|
||||||
|
icon={ImportExportIcon}
|
||||||
|
bgcolor="#5d89f7"
|
||||||
|
label={LL.UPLOAD_DOWNLOAD()}
|
||||||
|
text="Upload/Download Settings and Firmware"
|
||||||
|
to="upload"
|
||||||
|
/>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
{renderRestartDialog()}
|
||||||
|
{renderFactoryResetDialog()}
|
||||||
|
|
||||||
|
<Box mt={1} display="flex" flexWrap="wrap">
|
||||||
|
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
|
||||||
|
<ButtonRow>
|
||||||
|
<Button
|
||||||
|
startIcon={<PowerSettingsNewIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => setConfirmRestart(true)}
|
||||||
|
>
|
||||||
|
{LL.RESTART()}
|
||||||
|
</Button>
|
||||||
|
</ButtonRow>
|
||||||
|
</Box>
|
||||||
|
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||||
|
<ButtonRow>
|
||||||
|
<Button
|
||||||
|
startIcon={<SettingsBackupRestoreIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setConfirmFactoryReset(true)}
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
{LL.FACTORY_RESET()}
|
||||||
|
</Button>
|
||||||
|
</ButtonRow>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return <SectionContent>{restarting ? <RestartMonitor /> : content()}</SectionContent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Settings;
|
||||||
@@ -6,7 +6,7 @@ import { useState } from 'react';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { APSettings } from 'types';
|
import type { APSettingsType } from 'types';
|
||||||
import * as APApi from 'api/ap';
|
import * as APApi from 'api/ap';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
@@ -24,10 +24,10 @@ import { numberValue, updateValueDirty, useRest } from 'utils';
|
|||||||
|
|
||||||
import { createAPSettingsValidator, validate } from 'validators';
|
import { createAPSettingsValidator, validate } from 'validators';
|
||||||
|
|
||||||
export const isAPEnabled = ({ provision_mode }: APSettings) =>
|
export const isAPEnabled = ({ provision_mode }: APSettingsType) =>
|
||||||
provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED;
|
provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED;
|
||||||
|
|
||||||
const APSettingsForm: FC = () => {
|
const APSettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
loadData,
|
loadData,
|
||||||
saving,
|
saving,
|
||||||
@@ -39,7 +39,7 @@ const APSettingsForm: FC = () => {
|
|||||||
blocker,
|
blocker,
|
||||||
saveData,
|
saveData,
|
||||||
errorMessage
|
errorMessage
|
||||||
} = useRest<APSettings>({
|
} = useRest<APSettingsType>({
|
||||||
read: APApi.readAPSettings,
|
read: APApi.readAPSettings,
|
||||||
update: APApi.updateAPSettings
|
update: APApi.updateAPSettings
|
||||||
});
|
});
|
||||||
@@ -205,11 +205,11 @@ const APSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default APSettingsForm;
|
export default APSettings;
|
||||||
@@ -7,14 +7,14 @@ import { useRequest } from 'alova';
|
|||||||
import type { Theme } from '@mui/material';
|
import type { Theme } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { APStatus } from 'types';
|
import type { APStatusType } from 'types';
|
||||||
import * as APApi from 'api/ap';
|
import * as APApi from 'api/ap';
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { APNetworkStatus } from 'types';
|
import { APNetworkStatus } from 'types';
|
||||||
|
|
||||||
export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
export const apStatusHighlight = ({ status }: APStatusType, theme: Theme) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case APNetworkStatus.ACTIVE:
|
case APNetworkStatus.ACTIVE:
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main;
|
||||||
@@ -27,14 +27,14 @@ export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const APStatusForm: FC = () => {
|
const APStatus: FC = () => {
|
||||||
const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
|
const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const apStatus = ({ status }: APStatus) => {
|
const apStatus = ({ status }: APStatusType) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case APNetworkStatus.ACTIVE:
|
case APNetworkStatus.ACTIVE:
|
||||||
return LL.ACTIVE();
|
return LL.ACTIVE();
|
||||||
@@ -99,11 +99,7 @@ const APStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF(LL.ACCESS_POINT(1))} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default APStatusForm;
|
export default APStatus;
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
|
|
||||||
import APSettingsForm from './APSettingsForm';
|
import APSettings from './APSettings';
|
||||||
import APStatusForm from './APStatusForm';
|
import APStatus from './APStatus';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
@@ -15,28 +13,18 @@ const AccessPoint: FC = () => {
|
|||||||
|
|
||||||
useLayoutTitle(LL.ACCESS_POINT(0));
|
useLayoutTitle(LL.ACCESS_POINT(0));
|
||||||
|
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
|
||||||
|
|
||||||
const { routerTab } = useRouterTab();
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} />
|
||||||
<Tab value="status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
<Tab value="status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
||||||
<Tab value="settings" label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} disabled={!authenticatedContext.me.admin} />
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<APStatusForm />} />
|
<Route path="status" element={<APStatus />} />
|
||||||
<Route index element={<Navigate to="status" />} />
|
<Route path="settings" element={<APSettings />} />
|
||||||
<Route
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
path="settings"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<APSettingsForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/*" element={<Navigate replace to="status" />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import MqttSettingsForm from './MqttSettingsForm';
|
import MqttSettings from './MqttSettings';
|
||||||
import MqttStatusForm from './MqttStatusForm';
|
import MqttStatus from './MqttStatus';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
@@ -15,26 +13,18 @@ const Mqtt: FC = () => {
|
|||||||
|
|
||||||
useLayoutTitle('MQTT');
|
useLayoutTitle('MQTT');
|
||||||
|
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
|
||||||
const { routerTab } = useRouterTab();
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
|
<Tab value="settings" label={LL.SETTINGS_OF('MQTT')} />
|
||||||
<Tab value="status" label={LL.STATUS_OF('MQTT')} />
|
<Tab value="status" label={LL.STATUS_OF('MQTT')} />
|
||||||
<Tab value="settings" label={LL.SETTINGS_OF('MQTT')} disabled={!authenticatedContext.me.admin} />
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<MqttStatusForm />} />
|
<Route path="status" element={<MqttStatus />} />
|
||||||
<Route
|
<Route path="settings" element={<MqttSettings />} />
|
||||||
path="settings"
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<MqttSettingsForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/*" element={<Navigate replace to="status" />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useState } from 'react';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { MqttSettings } from 'types';
|
import type { MqttSettingsType } from 'types';
|
||||||
import * as MqttApi from 'api/mqtt';
|
import * as MqttApi from 'api/mqtt';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
@@ -21,7 +21,7 @@ import { numberValue, updateValueDirty, useRest } from 'utils';
|
|||||||
|
|
||||||
import { createMqttSettingsValidator, validate } from 'validators';
|
import { createMqttSettingsValidator, validate } from 'validators';
|
||||||
|
|
||||||
const MqttSettingsForm: FC = () => {
|
const MqttSettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
loadData,
|
loadData,
|
||||||
saving,
|
saving,
|
||||||
@@ -33,7 +33,7 @@ const MqttSettingsForm: FC = () => {
|
|||||||
blocker,
|
blocker,
|
||||||
saveData,
|
saveData,
|
||||||
errorMessage
|
errorMessage
|
||||||
} = useRest<MqttSettings>({
|
} = useRest<MqttSettingsType>({
|
||||||
read: MqttApi.readMqttSettings,
|
read: MqttApi.readMqttSettings,
|
||||||
update: MqttApi.updateMqttSettings
|
update: MqttApi.updateMqttSettings
|
||||||
});
|
});
|
||||||
@@ -72,6 +72,7 @@ const MqttSettingsForm: FC = () => {
|
|||||||
name="host"
|
name="host"
|
||||||
label={LL.ADDRESS_OF(LL.BROKER())}
|
label={LL.ADDRESS_OF(LL.BROKER())}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
multiline
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={data.host}
|
value={data.host}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
@@ -168,20 +169,24 @@ const MqttSettingsForm: FC = () => {
|
|||||||
<MenuItem value={2}>2</MenuItem>
|
<MenuItem value={2}>2</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
{data.rootCA !== undefined && (
|
|
||||||
<Grid item xs={12} sm={6}>
|
|
||||||
<ValidatedPasswordField
|
|
||||||
name="rootCA"
|
|
||||||
label={LL.CERT()}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={data.rootCA}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{data.enableTLS !== undefined && (
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={<Checkbox name="enableTLS" checked={data.enableTLS} onChange={updateFormValue} />}
|
||||||
|
label={LL.ENABLE_TLS()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{data.enableTLS === true && (
|
||||||
|
<ValidatedPasswordField
|
||||||
|
name="rootCA"
|
||||||
|
label={LL.CERT()}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.rootCA}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
||||||
@@ -269,6 +274,7 @@ const MqttSettingsForm: FC = () => {
|
|||||||
>
|
>
|
||||||
<MenuItem value={0}>Home Assistant</MenuItem>
|
<MenuItem value={0}>Home Assistant</MenuItem>
|
||||||
<MenuItem value={1}>Domoticz</MenuItem>
|
<MenuItem value={1}>Domoticz</MenuItem>
|
||||||
|
<MenuItem value={2}>Domoticz (latest)</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={4}>
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
@@ -382,6 +388,21 @@ const MqttSettingsForm: FC = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
|
<TextField
|
||||||
|
name="publish_time_water"
|
||||||
|
label={LL.MQTT_INT_WATER()}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: <InputAdornment position="end">{LL.SECONDS()}</InputAdornment>
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={numberValue(data.publish_time_water)}
|
||||||
|
type="number"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={4}>
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
<TextField
|
<TextField
|
||||||
name="publish_time_sensor"
|
name="publish_time_sensor"
|
||||||
@@ -443,11 +464,11 @@ const MqttSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('MQTT')} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MqttSettingsForm;
|
export default MqttSettings;
|
||||||
@@ -8,13 +8,13 @@ import { useRequest } from 'alova';
|
|||||||
import type { Theme } from '@mui/material';
|
import type { Theme } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { MqttStatus } from 'types';
|
import type { MqttStatusType } from 'types';
|
||||||
import * as MqttApi from 'api/mqtt';
|
import * as MqttApi from 'api/mqtt';
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { MqttDisconnectReason } from 'types';
|
import { MqttDisconnectReason } from 'types';
|
||||||
|
|
||||||
export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => {
|
export const mqttStatusHighlight = ({ enabled, connected }: MqttStatusType, theme: Theme) => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return theme.palette.info.main;
|
return theme.palette.info.main;
|
||||||
}
|
}
|
||||||
@@ -24,27 +24,27 @@ export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: T
|
|||||||
return theme.palette.error.main;
|
return theme.palette.error.main;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatus, theme: Theme) => {
|
export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatusType, theme: Theme) => {
|
||||||
if (mqtt_fails === 0) return theme.palette.success.main;
|
if (mqtt_fails === 0) return theme.palette.success.main;
|
||||||
if (mqtt_fails < 10) return theme.palette.warning.main;
|
if (mqtt_fails < 10) return theme.palette.warning.main;
|
||||||
|
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatus, theme: Theme) => {
|
export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatusType, theme: Theme) => {
|
||||||
if (mqtt_queued <= 1) return theme.palette.success.main;
|
if (mqtt_queued <= 1) return theme.palette.success.main;
|
||||||
|
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MqttStatusForm: FC = () => {
|
const MqttStatus: FC = () => {
|
||||||
const { data: data, send: loadData, error } = useRequest(MqttApi.readMqttStatus);
|
const { data: data, send: loadData, error } = useRequest(MqttApi.readMqttStatus);
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const mqttStatus = ({ enabled, connected, connect_count }: MqttStatus) => {
|
const mqttStatus = ({ enabled, connected, connect_count }: MqttStatusType) => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return LL.NOT_ENABLED();
|
return LL.NOT_ENABLED();
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ const MqttStatusForm: FC = () => {
|
|||||||
return LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '');
|
return LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : '');
|
||||||
};
|
};
|
||||||
|
|
||||||
const disconnectReason = ({ disconnect_reason }: MqttStatus) => {
|
const disconnectReason = ({ disconnect_reason }: MqttStatusType) => {
|
||||||
switch (disconnect_reason) {
|
switch (disconnect_reason) {
|
||||||
case MqttDisconnectReason.TCP_DISCONNECTED:
|
case MqttDisconnectReason.TCP_DISCONNECTED:
|
||||||
return 'TCP disconnected';
|
return 'TCP disconnected';
|
||||||
@@ -69,7 +69,7 @@ const MqttStatusForm: FC = () => {
|
|||||||
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
||||||
return 'Not authorized';
|
return 'Not authorized';
|
||||||
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
||||||
return 'TSL fingerprint invalid';
|
return 'TLS fingerprint invalid';
|
||||||
default:
|
default:
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
@@ -146,11 +146,7 @@ const MqttStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF('MQTT')} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MqttStatusForm;
|
export default MqttStatus;
|
||||||
@@ -1,24 +1,22 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { useCallback, useContext, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { Navigate, Routes, Route, useNavigate } from 'react-router-dom';
|
import { Navigate, Routes, Route, useNavigate } from 'react-router-dom';
|
||||||
import NetworkSettingsForm from './NetworkSettingsForm';
|
import NetworkSettings from './NetworkSettings';
|
||||||
import NetworkStatusForm from './NetworkStatusForm';
|
import NetworkStatus from './NetworkStatus';
|
||||||
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
||||||
import WiFiNetworkScanner from './WiFiNetworkScanner';
|
import WiFiNetworkScanner from './WiFiNetworkScanner';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { WiFiNetwork } from 'types';
|
import type { WiFiNetwork } from 'types';
|
||||||
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const NetworkConnection: FC = () => {
|
const Network: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle(LL.NETWORK(0));
|
useLayoutTitle(LL.NETWORK(0));
|
||||||
|
|
||||||
const { routerTab } = useRouterTab();
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [selectedNetwork, setSelectedNetwork] = useState<WiFiNetwork>();
|
const [selectedNetwork, setSelectedNetwork] = useState<WiFiNetwork>();
|
||||||
@@ -44,32 +42,18 @@ const NetworkConnection: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} />
|
||||||
<Tab value="status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
<Tab value="status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
||||||
<Tab value="scan" label={LL.NETWORK_SCAN()} disabled={!authenticatedContext.me.admin} />
|
<Tab value="scan" label={LL.NETWORK_SCAN()} />
|
||||||
<Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} disabled={!authenticatedContext.me.admin} />
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NetworkStatusForm />} />
|
<Route path="status" element={<NetworkStatus />} />
|
||||||
<Route
|
<Route path="scan" element={<WiFiNetworkScanner />} />
|
||||||
path="scan"
|
<Route path="settings" element={<NetworkSettings />} />
|
||||||
element={
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
<RequireAdmin>
|
|
||||||
<WiFiNetworkScanner />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="settings"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<NetworkSettingsForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/*" element={<Navigate replace to="status" />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</WiFiConnectionContext.Provider>
|
</WiFiConnectionContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NetworkConnection;
|
export default Network;
|
||||||
@@ -15,8 +15,8 @@ import {
|
|||||||
ListItemSecondaryAction,
|
ListItemSecondaryAction,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
Typography,
|
Typography,
|
||||||
InputAdornment,
|
TextField,
|
||||||
TextField
|
MenuItem
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
// eslint-disable-next-line import/named
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
@@ -28,7 +28,7 @@ import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { NetworkSettings } from 'types';
|
import type { NetworkSettingsType } from 'types';
|
||||||
import * as NetworkApi from 'api/network';
|
import * as NetworkApi from 'api/network';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import {
|
import {
|
||||||
@@ -43,12 +43,12 @@ import {
|
|||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
import { updateValueDirty, useRest } from 'utils';
|
||||||
|
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
import { createNetworkSettingsValidator } from 'validators/network';
|
import { createNetworkSettingsValidator } from 'validators/network';
|
||||||
|
|
||||||
const WiFiSettingsForm: FC = () => {
|
const NetworkSettings: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext);
|
const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext);
|
||||||
@@ -68,7 +68,7 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
saveData,
|
saveData,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
restartNeeded
|
restartNeeded
|
||||||
} = useRest<NetworkSettings>({
|
} = useRest<NetworkSettingsType>({
|
||||||
read: NetworkApi.readNetworkSettings,
|
read: NetworkApi.readNetworkSettings,
|
||||||
update: NetworkApi.updateNetworkSettings
|
update: NetworkApi.updateNetworkSettings
|
||||||
});
|
});
|
||||||
@@ -82,12 +82,13 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
if (selectedNetwork) {
|
if (selectedNetwork) {
|
||||||
updateState('networkSettings', (current_data) => ({
|
updateState('networkSettings', (current_data) => ({
|
||||||
ssid: selectedNetwork.ssid,
|
ssid: selectedNetwork.ssid,
|
||||||
password: '',
|
bssid: selectedNetwork.bssid,
|
||||||
|
password: current_data ? current_data.password : '',
|
||||||
hostname: current_data?.hostname,
|
hostname: current_data?.hostname,
|
||||||
static_ip_config: false,
|
static_ip_config: false,
|
||||||
enableIPv6: false,
|
enableIPv6: false,
|
||||||
bandwidth20: false,
|
bandwidth20: false,
|
||||||
tx_power: 20,
|
tx_power: 0,
|
||||||
nosleep: false,
|
nosleep: false,
|
||||||
enableMDNS: true,
|
enableMDNS: true,
|
||||||
enableCORS: false,
|
enableCORS: false,
|
||||||
@@ -117,6 +118,12 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
} catch (errors: any) {
|
} catch (errors: any) {
|
||||||
setFieldErrors(errors);
|
setFieldErrors(errors);
|
||||||
}
|
}
|
||||||
|
deselectNetwork();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCancel = async () => {
|
||||||
|
deselectNetwork();
|
||||||
|
await loadData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const restart = async () => {
|
const restart = async () => {
|
||||||
@@ -128,7 +135,7 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
<Typography variant="h6" color="primary">
|
||||||
WiFi
|
WiFi
|
||||||
</Typography>
|
</Typography>
|
||||||
{selectedNetwork ? (
|
{selectedNetwork ? (
|
||||||
@@ -139,10 +146,17 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={selectedNetwork.ssid}
|
primary={selectedNetwork.ssid}
|
||||||
secondary={'Security: ' + networkSecurityMode(selectedNetwork) + ', Ch: ' + selectedNetwork.channel}
|
secondary={
|
||||||
|
'Security: ' +
|
||||||
|
networkSecurityMode(selectedNetwork) +
|
||||||
|
', Ch: ' +
|
||||||
|
selectedNetwork.channel +
|
||||||
|
', bssid: ' +
|
||||||
|
selectedNetwork.bssid
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<IconButton onClick={deselectNetwork}>
|
<IconButton onClick={setCancel}>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
@@ -160,6 +174,16 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="bssid"
|
||||||
|
label={'BSSID (' + LL.NETWORK_BLANK_BSSID() + ')'}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.bssid}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors}
|
||||||
@@ -172,20 +196,29 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ValidatedTextField
|
<TextField
|
||||||
fieldErrors={fieldErrors}
|
|
||||||
name="tx_power"
|
name="tx_power"
|
||||||
label={LL.TX_POWER()}
|
label={LL.TX_POWER()}
|
||||||
InputProps={{
|
|
||||||
endAdornment: <InputAdornment position="end">dBm</InputAdornment>
|
|
||||||
}}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={numberValue(data.tx_power)}
|
value={data.tx_power}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
type="number"
|
|
||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
select
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>Auto</MenuItem>
|
||||||
|
<MenuItem value={78}>19.5 dBm</MenuItem>
|
||||||
|
<MenuItem value={76}>19 dBm</MenuItem>
|
||||||
|
<MenuItem value={74}>18.5 dBm</MenuItem>
|
||||||
|
<MenuItem value={68}>17 dBm</MenuItem>
|
||||||
|
<MenuItem value={60}>15 dBm</MenuItem>
|
||||||
|
<MenuItem value={52}>13 dBm</MenuItem>
|
||||||
|
<MenuItem value={44}>11 dBm</MenuItem>
|
||||||
|
<MenuItem value={34}>8.5 dBm</MenuItem>
|
||||||
|
<MenuItem value={28}>7 dBm</MenuItem>
|
||||||
|
<MenuItem value={20}>5 dBm</MenuItem>
|
||||||
|
<MenuItem value={8}>2 dBm</MenuItem>
|
||||||
|
</TextField>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox name="nosleep" checked={data.nosleep} onChange={updateFormValue} />}
|
control={<Checkbox name="nosleep" checked={data.nosleep} onChange={updateFormValue} />}
|
||||||
label={LL.NETWORK_DISABLE_SLEEP()}
|
label={LL.NETWORK_DISABLE_SLEEP()}
|
||||||
@@ -226,10 +259,12 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<BlockFormControlLabel
|
{data.enableIPv6 !== undefined && (
|
||||||
control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />}
|
<BlockFormControlLabel
|
||||||
label={LL.NETWORK_ENABLE_IPV6()}
|
control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />}
|
||||||
/>
|
label={LL.NETWORK_ENABLE_IPV6()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox name="static_ip_config" checked={data.static_ip_config} onChange={updateFormValue} />}
|
control={<Checkbox name="static_ip_config" checked={data.static_ip_config} onChange={updateFormValue} />}
|
||||||
label={LL.NETWORK_FIXED_IP()}
|
label={LL.NETWORK_FIXED_IP()}
|
||||||
@@ -289,14 +324,14 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{restartNeeded && (
|
{restartNeeded && (
|
||||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
|
||||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||||
{LL.RESTART()}
|
{LL.RESTART()}
|
||||||
</Button>
|
</Button>
|
||||||
</MessageBox>
|
</MessageBox>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!restartNeeded && dirtyFlags && dirtyFlags.length !== 0 && (
|
{!restartNeeded && (selectedNetwork || (dirtyFlags && dirtyFlags.length !== 0)) && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
@@ -325,11 +360,11 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
{restarting ? <RestartMonitor /> : content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WiFiSettingsForm;
|
export default NetworkSettings;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||||
import DnsIcon from '@mui/icons-material/Dns';
|
import DnsIcon from '@mui/icons-material/Dns';
|
||||||
|
import GiteIcon from '@mui/icons-material/Gite';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import RouterIcon from '@mui/icons-material/Router';
|
import RouterIcon from '@mui/icons-material/Router';
|
||||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||||
@@ -10,18 +11,18 @@ import { useRequest } from 'alova';
|
|||||||
import type { Theme } from '@mui/material';
|
import type { Theme } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { NetworkStatus } from 'types';
|
import type { NetworkStatusType } from 'types';
|
||||||
import * as NetworkApi from 'api/network';
|
import * as NetworkApi from 'api/network';
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { NetworkConnectionStatus } from 'types';
|
import { NetworkConnectionStatus } from 'types';
|
||||||
|
|
||||||
const isConnected = ({ status }: NetworkStatus) =>
|
const isConnected = ({ status }: NetworkStatusType) =>
|
||||||
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
|
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
|
||||||
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
||||||
|
|
||||||
const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => {
|
const networkStatusHighlight = ({ status }: NetworkStatusType, theme: Theme) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||||
@@ -38,17 +39,27 @@ const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
|
const networkQualityHighlight = ({ rssi }: NetworkStatusType, theme: Theme) => {
|
||||||
export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
if (rssi <= -85) {
|
||||||
|
return theme.palette.error.main;
|
||||||
|
} else if (rssi <= -75) {
|
||||||
|
return theme.palette.warning.main;
|
||||||
|
}
|
||||||
|
return theme.palette.success.main;
|
||||||
|
};
|
||||||
|
|
||||||
const dnsServers = ({ dns_ip_1, dns_ip_2 }: NetworkStatus) => {
|
export const isWiFi = ({ status }: NetworkStatusType) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
|
||||||
|
export const isEthernet = ({ status }: NetworkStatusType) =>
|
||||||
|
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
||||||
|
|
||||||
|
const dnsServers = ({ dns_ip_1, dns_ip_2 }: NetworkStatusType) => {
|
||||||
if (!dns_ip_1) {
|
if (!dns_ip_1) {
|
||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
return dns_ip_1 + (!dns_ip_2 || dns_ip_2 === '0.0.0.0' ? '' : ',' + dns_ip_2);
|
return dns_ip_1 + (!dns_ip_2 || dns_ip_2 === '0.0.0.0' ? '' : ',' + dns_ip_2);
|
||||||
};
|
};
|
||||||
|
|
||||||
const IPs = (status: NetworkStatus) => {
|
const IPs = (status: NetworkStatusType) => {
|
||||||
if (!status.local_ipv6 || status.local_ipv6 === '0000:0000:0000:0000:0000:0000:0000:0000') {
|
if (!status.local_ipv6 || status.local_ipv6 === '0000:0000:0000:0000:0000:0000:0000:0000') {
|
||||||
return status.local_ip;
|
return status.local_ip;
|
||||||
}
|
}
|
||||||
@@ -58,14 +69,14 @@ const IPs = (status: NetworkStatus) => {
|
|||||||
return status.local_ip + ', ' + status.local_ipv6;
|
return status.local_ip + ', ' + status.local_ipv6;
|
||||||
};
|
};
|
||||||
|
|
||||||
const NetworkStatusForm: FC = () => {
|
const NetworkStatus: FC = () => {
|
||||||
const { data: data, send: loadData, error } = useRequest(NetworkApi.readNetworkStatus);
|
const { data: data, send: loadData, error } = useRequest(NetworkApi.readNetworkStatus);
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const networkStatus = ({ status }: NetworkStatus) => {
|
const networkStatus = ({ status }: NetworkStatusType) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||||
return LL.INACTIVE(1);
|
return LL.INACTIVE(1);
|
||||||
@@ -106,15 +117,24 @@ const NetworkStatusForm: FC = () => {
|
|||||||
<ListItemText primary="Status" secondary={networkStatus(data)} />
|
<ListItemText primary="Status" secondary={networkStatus(data)} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: networkStatusHighlight(data, theme) }}>
|
||||||
|
<GiteIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary="Hostname" secondary={data.hostname} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
{isWiFi(data) && (
|
{isWiFi(data) && (
|
||||||
<>
|
<>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar>
|
<Avatar sx={{ bgcolor: networkQualityHighlight(data, theme) }}>
|
||||||
<SettingsInputAntennaIcon />
|
<SettingsInputAntennaIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText primary="SSID" secondary={data.ssid} />
|
<ListItemText primary="SSID (RSSI)" secondary={data.ssid + ' (' + data.rssi + ' dBm)'} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
</>
|
</>
|
||||||
@@ -174,11 +194,7 @@ const NetworkStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF(LL.NETWORK(1))} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NetworkStatusForm;
|
export default NetworkStatus;
|
||||||
@@ -56,7 +56,7 @@ const WiFiNetworkScanner: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.NETWORK_SCANNER()}>
|
<SectionContent>
|
||||||
{renderNetworkScanner()}
|
{renderNetworkScanner()}
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
import LockOpenIcon from '@mui/icons-material/LockOpen';
|
import LockOpenIcon from '@mui/icons-material/LockOpen';
|
||||||
import WifiIcon from '@mui/icons-material/Wifi';
|
import WifiIcon from '@mui/icons-material/Wifi';
|
||||||
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText } from '@mui/material';
|
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText, useTheme } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
||||||
|
import type { Theme } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import type { WiFiNetwork, WiFiNetworkList } from 'types';
|
import type { WiFiNetwork, WiFiNetworkList } from 'types';
|
||||||
import { MessageBox } from 'components';
|
import { MessageBox } from 'components';
|
||||||
@@ -42,8 +43,18 @@ export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const networkQualityHighlight = ({ rssi }: WiFiNetwork, theme: Theme) => {
|
||||||
|
if (rssi <= -85) {
|
||||||
|
return theme.palette.error.main;
|
||||||
|
} else if (rssi <= -75) {
|
||||||
|
return theme.palette.warning.main;
|
||||||
|
}
|
||||||
|
return theme.palette.success.main;
|
||||||
|
};
|
||||||
|
|
||||||
const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const wifiConnectionContext = useContext(WiFiConnectionContext);
|
const wifiConnectionContext = useContext(WiFiConnectionContext);
|
||||||
|
|
||||||
@@ -54,11 +65,13 @@ const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
|
|||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={network.ssid}
|
primary={network.ssid}
|
||||||
secondary={'Security: ' + networkSecurityMode(network) + ', Ch: ' + network.channel}
|
secondary={
|
||||||
|
'Security: ' + networkSecurityMode(network) + ', Ch: ' + network.channel + ', bssid: ' + network.bssid
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Badge badgeContent={network.rssi + 'db'}>
|
<Badge badgeContent={network.rssi + 'dBm'}>
|
||||||
<WifiIcon />
|
<WifiIcon sx={{ color: networkQualityHighlight(network, theme) }} />
|
||||||
</Badge>
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { selectedTimeZone, timeZoneSelectItems, TIME_ZONES } from './TZ';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { NTPSettings } from 'types';
|
import type { NTPSettingsType } from 'types';
|
||||||
import * as NTPApi from 'api/ntp';
|
import * as NTPApi from 'api/ntp';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
@@ -23,7 +23,7 @@ import { updateValueDirty, useRest } from 'utils';
|
|||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
|
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
|
||||||
|
|
||||||
const NTPSettingsForm: FC = () => {
|
const NTPSettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
loadData,
|
loadData,
|
||||||
saving,
|
saving,
|
||||||
@@ -35,7 +35,7 @@ const NTPSettingsForm: FC = () => {
|
|||||||
blocker,
|
blocker,
|
||||||
saveData,
|
saveData,
|
||||||
errorMessage
|
errorMessage
|
||||||
} = useRest<NTPSettings>({
|
} = useRest<NTPSettingsType>({
|
||||||
read: NTPApi.readNTPSettings,
|
read: NTPApi.readNTPSettings,
|
||||||
update: NTPApi.updateNTPSettings
|
update: NTPApi.updateNTPSettings
|
||||||
});
|
});
|
||||||
@@ -130,11 +130,11 @@ const NTPSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('NTP')} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NTPSettingsForm;
|
export default NTPSettings;
|
||||||
@@ -22,44 +22,26 @@ import {
|
|||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { useContext, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import type { Theme } from '@mui/material';
|
import type { Theme } from '@mui/material';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { NTPStatus } from 'types';
|
import type { NTPStatusType } from 'types';
|
||||||
import { dialogStyle } from 'CustomTheme';
|
import { dialogStyle } from 'CustomTheme';
|
||||||
import * as NTPApi from 'api/ntp';
|
import * as NTPApi from 'api/ntp';
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { NTPSyncStatus } from 'types';
|
import { NTPSyncStatus } from 'types';
|
||||||
import { formatDateTime, formatLocalDateTime } from 'utils';
|
import { formatDateTime, formatLocalDateTime } from 'utils';
|
||||||
|
|
||||||
export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE;
|
const NTPStatus: FC = () => {
|
||||||
export const isNtpEnabled = ({ status }: NTPStatus) => status !== NTPSyncStatus.NTP_DISABLED;
|
|
||||||
|
|
||||||
export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
|
||||||
switch (status) {
|
|
||||||
case NTPSyncStatus.NTP_DISABLED:
|
|
||||||
return theme.palette.info.main;
|
|
||||||
case NTPSyncStatus.NTP_INACTIVE:
|
|
||||||
return theme.palette.error.main;
|
|
||||||
case NTPSyncStatus.NTP_ACTIVE:
|
|
||||||
return theme.palette.success.main;
|
|
||||||
default:
|
|
||||||
return theme.palette.error.main;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const NTPStatusForm: FC = () => {
|
|
||||||
const { data: data, send: loadData, error } = useRequest(NTPApi.readNTPStatus);
|
const { data: data, send: loadData, error } = useRequest(NTPApi.readNTPStatus);
|
||||||
|
|
||||||
const [localTime, setLocalTime] = useState<string>('');
|
const [localTime, setLocalTime] = useState<string>('');
|
||||||
const [settingTime, setSettingTime] = useState<boolean>(false);
|
const [settingTime, setSettingTime] = useState<boolean>(false);
|
||||||
const [processing, setProcessing] = useState<boolean>(false);
|
const [processing, setProcessing] = useState<boolean>(false);
|
||||||
const { me } = useContext(AuthenticatedContext);
|
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
@@ -69,6 +51,22 @@ const NTPStatusForm: FC = () => {
|
|||||||
|
|
||||||
NTPApi.updateTime;
|
NTPApi.updateTime;
|
||||||
|
|
||||||
|
const isNtpActive = ({ status }: NTPStatusType) => status === NTPSyncStatus.NTP_ACTIVE;
|
||||||
|
const isNtpEnabled = ({ status }: NTPStatusType) => status !== NTPSyncStatus.NTP_DISABLED;
|
||||||
|
|
||||||
|
const ntpStatusHighlight = ({ status }: NTPStatusType, theme: Theme) => {
|
||||||
|
switch (status) {
|
||||||
|
case NTPSyncStatus.NTP_DISABLED:
|
||||||
|
return theme.palette.info.main;
|
||||||
|
case NTPSyncStatus.NTP_INACTIVE:
|
||||||
|
return theme.palette.error.main;
|
||||||
|
case NTPSyncStatus.NTP_ACTIVE:
|
||||||
|
return theme.palette.success.main;
|
||||||
|
default:
|
||||||
|
return theme.palette.error.main;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const updateLocalTime = (event: React.ChangeEvent<HTMLInputElement>) => setLocalTime(event.target.value);
|
const updateLocalTime = (event: React.ChangeEvent<HTMLInputElement>) => setLocalTime(event.target.value);
|
||||||
|
|
||||||
const openSetTime = () => {
|
const openSetTime = () => {
|
||||||
@@ -78,7 +76,7 @@ const NTPStatusForm: FC = () => {
|
|||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const ntpStatus = ({ status }: NTPStatus) => {
|
const ntpStatus = ({ status }: NTPStatusType) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NTPSyncStatus.NTP_DISABLED:
|
case NTPSyncStatus.NTP_DISABLED:
|
||||||
return LL.NOT_ENABLED();
|
return LL.NOT_ENABLED();
|
||||||
@@ -201,7 +199,7 @@ const NTPStatusForm: FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
</Box>
|
</Box>
|
||||||
{me.admin && data && !isNtpActive(data) && (
|
{data && !isNtpActive(data) && (
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button onClick={openSetTime} variant="outlined" color="primary" startIcon={<AccessTimeIcon />}>
|
<Button onClick={openSetTime} variant="outlined" color="primary" startIcon={<AccessTimeIcon />}>
|
||||||
@@ -216,11 +214,7 @@ const NTPStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF('NTP')} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NTPStatusForm;
|
export default NTPStatus;
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import NTPSettingsForm from './NTPSettingsForm';
|
import NTPSettings from './NTPSettings';
|
||||||
import NTPStatusForm from './NTPStatusForm';
|
import NTPStatus from './NTPStatus';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
@@ -14,26 +12,18 @@ const NetworkTime: FC = () => {
|
|||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle('NTP');
|
useLayoutTitle('NTP');
|
||||||
|
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
|
||||||
const { routerTab } = useRouterTab();
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
|
<Tab value="settings" label={LL.SETTINGS_OF('NTP')} />
|
||||||
<Tab value="status" label={LL.STATUS_OF('NTP')} />
|
<Tab value="status" label={LL.STATUS_OF('NTP')} />
|
||||||
<Tab value="settings" label={LL.SETTINGS_OF('NTP')} disabled={!authenticatedContext.me.admin} />
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NTPStatusForm />} />
|
<Route path="status" element={<NTPStatus />} />
|
||||||
<Route
|
<Route path="settings" element={<NTPSettings />} />
|
||||||
path="settings"
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<NTPSettingsForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/*" element={<Navigate replace to="status" />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useState } from 'react';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { OTASettings } from 'types';
|
import type { OTASettingsType } from 'types';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
@@ -14,7 +14,8 @@ import {
|
|||||||
SectionContent,
|
SectionContent,
|
||||||
ValidatedPasswordField,
|
ValidatedPasswordField,
|
||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
BlockNavigation
|
BlockNavigation,
|
||||||
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
@@ -23,7 +24,7 @@ import { numberValue, updateValueDirty, useRest } from 'utils';
|
|||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
import { OTA_SETTINGS_VALIDATOR } from 'validators/system';
|
import { OTA_SETTINGS_VALIDATOR } from 'validators/system';
|
||||||
|
|
||||||
const OTASettingsForm: FC = () => {
|
const OTASettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
loadData,
|
loadData,
|
||||||
saveData,
|
saveData,
|
||||||
@@ -35,7 +36,7 @@ const OTASettingsForm: FC = () => {
|
|||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
blocker,
|
blocker,
|
||||||
errorMessage
|
errorMessage
|
||||||
} = useRest<OTASettings>({
|
} = useRest<OTASettingsType>({
|
||||||
read: SystemApi.readOTASettings,
|
read: SystemApi.readOTASettings,
|
||||||
update: SystemApi.updateOTASettings
|
update: SystemApi.updateOTASettings
|
||||||
});
|
});
|
||||||
@@ -61,6 +62,8 @@ const OTASettingsForm: FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useLayoutTitle('OTA');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
@@ -117,11 +120,11 @@ const OTASettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('OTA')} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OTASettingsForm;
|
export default OTASettings;
|
||||||
@@ -37,7 +37,8 @@ const GenerateToken: FC<GenerateTokenProps> = ({ username, onClose }) => {
|
|||||||
if (open) {
|
if (open) {
|
||||||
void generateToken();
|
void generateToken();
|
||||||
}
|
}
|
||||||
}, [open, generateToken]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm">
|
<Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm">
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-li
|
|||||||
import { useTheme } from '@table-library/react-table-library/theme';
|
import { useTheme } from '@table-library/react-table-library/theme';
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
|
|
||||||
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
import { useBlocker } from 'react-router-dom';
|
||||||
import GenerateToken from './GenerateToken';
|
import GenerateToken from './GenerateToken';
|
||||||
import UserForm from './UserForm';
|
import User from './User';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import type { SecuritySettings, User } from 'types';
|
import type { SecuritySettingsType, UserType } from 'types';
|
||||||
import * as SecurityApi from 'api/security';
|
import * as SecurityApi from 'api/security';
|
||||||
import { ButtonRow, FormLoader, MessageBox, SectionContent, BlockNavigation } from 'components';
|
import { ButtonRow, FormLoader, MessageBox, SectionContent, BlockNavigation } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
@@ -24,13 +24,13 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import { useRest } from 'utils';
|
import { useRest } from 'utils';
|
||||||
import { createUserValidator } from 'validators';
|
import { createUserValidator } from 'validators';
|
||||||
|
|
||||||
const ManageUsersForm: FC = () => {
|
const ManageUsers: FC = () => {
|
||||||
const { loadData, saveData, saving, data, updateDataValue, errorMessage } = useRest<SecuritySettings>({
|
const { loadData, saveData, saving, data, updateDataValue, errorMessage } = useRest<SecuritySettingsType>({
|
||||||
read: SecurityApi.readSecuritySettings,
|
read: SecurityApi.readSecuritySettings,
|
||||||
update: SecurityApi.updateSecuritySettings
|
update: SecurityApi.updateSecuritySettings
|
||||||
});
|
});
|
||||||
|
|
||||||
const [user, setUser] = useState<User>();
|
const [user, setUser] = useState<UserType>();
|
||||||
const [creating, setCreating] = useState<boolean>(false);
|
const [creating, setCreating] = useState<boolean>(false);
|
||||||
const [changed, setChanged] = useState<number>(0);
|
const [changed, setChanged] = useState<number>(0);
|
||||||
const [generatingToken, setGeneratingToken] = useState<string>();
|
const [generatingToken, setGeneratingToken] = useState<string>();
|
||||||
@@ -86,7 +86,7 @@ const ManageUsersForm: FC = () => {
|
|||||||
|
|
||||||
const noAdminConfigured = () => !data.users.find((u) => u.admin);
|
const noAdminConfigured = () => !data.users.find((u) => u.admin);
|
||||||
|
|
||||||
const removeUser = (toRemove: User) => {
|
const removeUser = (toRemove: UserType) => {
|
||||||
const users = data.users.filter((u) => u.username !== toRemove.username);
|
const users = data.users.filter((u) => u.username !== toRemove.username);
|
||||||
updateDataValue({ ...data, users });
|
updateDataValue({ ...data, users });
|
||||||
setChanged(changed + 1);
|
setChanged(changed + 1);
|
||||||
@@ -101,7 +101,7 @@ const ManageUsersForm: FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const editUser = (toEdit: User) => {
|
const editUser = (toEdit: UserType) => {
|
||||||
setCreating(false);
|
setCreating(false);
|
||||||
setUser({ ...toEdit });
|
setUser({ ...toEdit });
|
||||||
};
|
};
|
||||||
@@ -219,7 +219,7 @@ const ManageUsersForm: FC = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<GenerateToken username={generatingToken} onClose={closeGenerateToken} />
|
<GenerateToken username={generatingToken} onClose={closeGenerateToken} />
|
||||||
<UserForm
|
<User
|
||||||
user={user}
|
user={user}
|
||||||
setUser={setUser}
|
setUser={setUser}
|
||||||
creating={creating}
|
creating={creating}
|
||||||
@@ -232,11 +232,11 @@ const ManageUsersForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.MANAGE_USERS()} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ManageUsersForm;
|
export default ManageUsers;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
import ManageUsersForm from './ManageUsersForm';
|
import ManageUsers from './ManageUsers';
|
||||||
import SecuritySettingsForm from './SecuritySettingsForm';
|
import SecuritySettings from './SecuritySettings';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
|
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
|
||||||
@@ -17,13 +17,13 @@ const Security: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="users" label={LL.MANAGE_USERS()} />
|
|
||||||
<Tab value="settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
||||||
|
<Tab value="users" label={LL.MANAGE_USERS()} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="users" element={<ManageUsersForm />} />
|
<Route path="users" element={<ManageUsers />} />
|
||||||
<Route path="settings" element={<SecuritySettingsForm />} />
|
<Route path="settings" element={<SecuritySettings />} />
|
||||||
<Route path="/*" element={<Navigate replace to="users" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import { useContext, useState } from 'react';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { SecuritySettings } from 'types';
|
import type { SecuritySettingsType } from 'types';
|
||||||
import * as SecurityApi from 'api/security';
|
import * as SecurityApi from 'api/security';
|
||||||
import { ButtonRow, FormLoader, MessageBox, SectionContent, ValidatedPasswordField, BlockNavigation } from 'components';
|
import { ButtonRow, FormLoader, MessageBox, SectionContent, ValidatedPasswordField, BlockNavigation } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { updateValueDirty, useRest } from 'utils';
|
import { updateValueDirty, useRest } from 'utils';
|
||||||
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
|
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
|
||||||
|
|
||||||
const SecuritySettingsForm: FC = () => {
|
const SecuritySettings: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
@@ -29,7 +29,7 @@ const SecuritySettingsForm: FC = () => {
|
|||||||
blocker,
|
blocker,
|
||||||
saveData,
|
saveData,
|
||||||
errorMessage
|
errorMessage
|
||||||
} = useRest<SecuritySettings>({
|
} = useRest<SecuritySettingsType>({
|
||||||
read: SecurityApi.readSecuritySettings,
|
read: SecurityApi.readSecuritySettings,
|
||||||
update: SecurityApi.updateSecuritySettings
|
update: SecurityApi.updateSecuritySettings
|
||||||
});
|
});
|
||||||
@@ -96,11 +96,11 @@ const SecuritySettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.SECURITY(1))} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SecuritySettingsForm;
|
export default SecuritySettings;
|
||||||
@@ -8,7 +8,7 @@ import type Schema from 'async-validator';
|
|||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { User } from 'types';
|
import type { UserType } from 'types';
|
||||||
import { dialogStyle } from 'CustomTheme';
|
import { dialogStyle } from 'CustomTheme';
|
||||||
import { BlockFormControlLabel, ValidatedPasswordField, ValidatedTextField } from 'components';
|
import { BlockFormControlLabel, ValidatedPasswordField, ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
@@ -19,14 +19,14 @@ interface UserFormProps {
|
|||||||
creating: boolean;
|
creating: boolean;
|
||||||
validator: Schema;
|
validator: Schema;
|
||||||
|
|
||||||
user?: User;
|
user?: UserType;
|
||||||
setUser: React.Dispatch<React.SetStateAction<User | undefined>>;
|
setUser: React.Dispatch<React.SetStateAction<UserType | undefined>>;
|
||||||
|
|
||||||
onDoneEditing: () => void;
|
onDoneEditing: () => void;
|
||||||
onCancelEditing: () => void;
|
onCancelEditing: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserForm: FC<UserFormProps> = ({ creating, validator, user, setUser, onDoneEditing, onCancelEditing }) => {
|
const User: FC<UserFormProps> = ({ creating, validator, user, setUser, onDoneEditing, onCancelEditing }) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const updateFormValue = updateValue(setUser);
|
const updateFormValue = updateValue(setUser);
|
||||||
@@ -104,4 +104,4 @@ const UserForm: FC<UserFormProps> = ({ creating, validator, user, setUser, onDon
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserForm;
|
export default User;
|
||||||
154
interface/src/framework/system/ESPSystemStatus.tsx
Normal file
154
interface/src/framework/system/ESPSystemStatus.tsx
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import AppsIcon from '@mui/icons-material/Apps';
|
||||||
|
import DeveloperBoardIcon from '@mui/icons-material/DeveloperBoard';
|
||||||
|
import DevicesIcon from '@mui/icons-material/Devices';
|
||||||
|
import FolderIcon from '@mui/icons-material/Folder';
|
||||||
|
import MemoryIcon from '@mui/icons-material/Memory';
|
||||||
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
|
import SdCardAlertIcon from '@mui/icons-material/SdCardAlert';
|
||||||
|
import SdStorageIcon from '@mui/icons-material/SdStorage';
|
||||||
|
import { Avatar, Box, Button, Divider, List, ListItem, ListItemAvatar, ListItemText } from '@mui/material';
|
||||||
|
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
|
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
|
function formatNumber(num: number) {
|
||||||
|
return new Intl.NumberFormat().format(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ESPSystemStatus: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
useLayoutTitle(LL.STATUS_OF('ESP32'));
|
||||||
|
|
||||||
|
const { data: data, send: loadData, error } = useRequest(SystemApi.readESPSystemStatus, { force: true });
|
||||||
|
|
||||||
|
const content = () => {
|
||||||
|
if (!data) {
|
||||||
|
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<DevicesIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary="SDK" secondary={data.arduino_version + ' / ESP-IDF ' + data.sdk_version} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<DeveloperBoardIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary="CPU"
|
||||||
|
secondary={
|
||||||
|
data.esp_platform +
|
||||||
|
'/' +
|
||||||
|
data.cpu_type +
|
||||||
|
' (rev.' +
|
||||||
|
data.cpu_rev +
|
||||||
|
', ' +
|
||||||
|
(data.cpu_cores == 1 ? 'single-core)' : 'dual-core)') +
|
||||||
|
' @ ' +
|
||||||
|
data.cpu_freq_mhz +
|
||||||
|
' Mhz'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<MemoryIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.HEAP()}
|
||||||
|
secondary={formatNumber(data.free_heap) + ' KB / ' + formatNumber(data.max_alloc_heap) + ' KB '}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{data.psram_size !== undefined && data.free_psram !== undefined && (
|
||||||
|
<>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<AppsIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.PSRAM()}
|
||||||
|
secondary={formatNumber(data.psram_size) + ' KB / ' + formatNumber(data.free_psram) + ' KB'}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<SdStorageIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.FLASH()}
|
||||||
|
secondary={
|
||||||
|
formatNumber(data.flash_chip_size) + ' KB / ' + (data.flash_chip_speed / 1000000).toFixed(0) + ' MHz'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<SdCardAlertIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.APPSIZE()}
|
||||||
|
secondary={
|
||||||
|
data.partition + ': ' + formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<FolderIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.FILESYSTEM()}
|
||||||
|
secondary={formatNumber(data.fs_used) + ' KB / ' + formatNumber(data.fs_free) + ' KB'}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
</List>
|
||||||
|
<Box display="flex" flexWrap="wrap">
|
||||||
|
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
|
||||||
|
<ButtonRow>
|
||||||
|
<Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={loadData}>
|
||||||
|
{LL.REFRESH()}
|
||||||
|
</Button>
|
||||||
|
</ButtonRow>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ESPSystemStatus;
|
||||||
@@ -1,53 +1,42 @@
|
|||||||
import { Tab } from '@mui/material';
|
import { Tab } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
import { useContext, type FC } from 'react';
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
import OTASettingsForm from './OTASettingsForm';
|
|
||||||
import SystemLog from './SystemLog';
|
import SystemLog from './SystemLog';
|
||||||
import SystemStatusForm from './SystemStatusForm';
|
import SystemStatus from './SystemStatus';
|
||||||
import UploadFileForm from './UploadFileForm';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from 'components';
|
import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import SystemActivity from 'project/SystemActivity';
|
||||||
|
|
||||||
const System: FC = () => {
|
const System: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
useLayoutTitle(LL.SYSTEM(0));
|
useLayoutTitle(LL.SYSTEM(0));
|
||||||
|
|
||||||
const { me } = useContext(AuthenticatedContext);
|
|
||||||
const { routerTab } = useRouterTab();
|
const { routerTab } = useRouterTab();
|
||||||
|
const { me } = useContext(AuthenticatedContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="status" label={LL.STATUS_OF(LL.SYSTEM(1))} />
|
<Tab value="status" label={LL.STATUS_OF('')} />
|
||||||
<Tab value="log" label={LL.LOG_OF(LL.SYSTEM(2))} />
|
<Tab value="activity" label={LL.ACTIVITY()} />
|
||||||
<Tab value="ota" label={LL.SETTINGS_OF('OTA')} disabled={!me.admin} />
|
<Tab disabled={!me.admin} value="log" label={me.admin ? LL.LOG_OF('') : ''} />
|
||||||
<Tab value="upload" label={LL.UPLOAD_DOWNLOAD()} disabled={!me.admin} />
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<SystemStatusForm />} />
|
<Route path="status" element={<SystemStatus />} />
|
||||||
<Route path="log" element={<SystemLog />} />
|
<Route path="activity" element={<SystemActivity />} />
|
||||||
<Route
|
<Route
|
||||||
path="ota"
|
path="log"
|
||||||
element={
|
element={
|
||||||
<RequireAdmin>
|
<RequireAdmin>
|
||||||
<OTASettingsForm />
|
<SystemLog />
|
||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route path="*" element={<Navigate replace to="status" />} />
|
||||||
path="upload"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<UploadFileForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="/*" element={<Navigate replace to="status" />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { addAccessTokenParameter } from 'api/authentication';
|
|||||||
import { EVENT_SOURCE_ROOT } from 'api/endpoints';
|
import { EVENT_SOURCE_ROOT } from 'api/endpoints';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
|
|
||||||
import { SectionContent, FormLoader, BlockFormControlLabel, BlockNavigation } from 'components';
|
import { SectionContent, FormLoader, BlockFormControlLabel, BlockNavigation, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { LogLevel } from 'types';
|
import { LogLevel } from 'types';
|
||||||
@@ -50,6 +50,8 @@ const levelLabel = (level: LogLevel) => {
|
|||||||
const SystemLog: FC = () => {
|
const SystemLog: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
useLayoutTitle(LL.LOG_OF(''));
|
||||||
|
|
||||||
const { loadData, data, updateDataValue, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =
|
const { loadData, data, updateDataValue, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =
|
||||||
useRest<LogSettings>({
|
useRest<LogSettings>({
|
||||||
read: SystemApi.readLogSettings,
|
read: SystemApi.readLogSettings,
|
||||||
@@ -232,7 +234,7 @@ const SystemLog: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.LOG_OF(LL.SYSTEM(2))} titleGutter id="log-window">
|
<SectionContent id="log-window">
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
297
interface/src/framework/system/SystemStatus.tsx
Normal file
297
interface/src/framework/system/SystemStatus.tsx
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CastIcon from '@mui/icons-material/Cast';
|
||||||
|
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||||
|
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
|
||||||
|
import MemoryIcon from '@mui/icons-material/Memory';
|
||||||
|
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
||||||
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
|
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||||
|
import TimerIcon from '@mui/icons-material/Timer';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Divider,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemAvatar,
|
||||||
|
ListItemText,
|
||||||
|
useTheme
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import { useContext, type FC, useState } from 'react';
|
||||||
|
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { dialogStyle } from 'CustomTheme';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
|
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||||
|
import ListMenuItem from 'components/layout/ListMenuItem';
|
||||||
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import * as EMSESP from 'project/api';
|
||||||
|
import { busConnectionStatus } from 'project/types';
|
||||||
|
import { NTPSyncStatus } from 'types';
|
||||||
|
|
||||||
|
const SystemStatus: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
useLayoutTitle(LL.STATUS_OF(''));
|
||||||
|
|
||||||
|
const { me } = useContext(AuthenticatedContext);
|
||||||
|
|
||||||
|
const [confirmScan, setConfirmScan] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus, { force: true });
|
||||||
|
|
||||||
|
const { send: scanDevices } = useRequest(EMSESP.scanDevices, {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const formatDurationSec = (duration_sec: number) => {
|
||||||
|
const days = Math.trunc((duration_sec * 1000) / 86400000);
|
||||||
|
const hours = Math.trunc((duration_sec * 1000) / 3600000) % 24;
|
||||||
|
const minutes = Math.trunc((duration_sec * 1000) / 60000) % 60;
|
||||||
|
const seconds = Math.trunc((duration_sec * 1000) / 1000) % 60;
|
||||||
|
|
||||||
|
let formatted = '';
|
||||||
|
if (days) {
|
||||||
|
formatted += LL.NUM_DAYS({ num: days }) + ' ';
|
||||||
|
}
|
||||||
|
if (hours) {
|
||||||
|
formatted += LL.NUM_HOURS({ num: hours }) + ' ';
|
||||||
|
}
|
||||||
|
if (minutes) {
|
||||||
|
formatted += LL.NUM_MINUTES({ num: minutes }) + ' ';
|
||||||
|
}
|
||||||
|
formatted += LL.NUM_SECONDS({ num: seconds });
|
||||||
|
return formatted;
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatNumber(num: number) {
|
||||||
|
return new Intl.NumberFormat().format(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
const busStatus = () => {
|
||||||
|
if (data) {
|
||||||
|
switch (data.status) {
|
||||||
|
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||||
|
return LL.CONNECTED(0) + ' (' + formatDurationSec(data.bus_uptime) + ')';
|
||||||
|
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||||
|
return LL.TX_ISSUES();
|
||||||
|
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||||
|
return LL.DISCONNECTED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Unknown';
|
||||||
|
};
|
||||||
|
|
||||||
|
const busStatusHighlight = () => {
|
||||||
|
switch (data.status) {
|
||||||
|
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||||
|
return theme.palette.warning.main;
|
||||||
|
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||||
|
return theme.palette.success.main;
|
||||||
|
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||||
|
return theme.palette.error.main;
|
||||||
|
default:
|
||||||
|
return theme.palette.warning.main;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ntpStatus = () => {
|
||||||
|
switch (data.ntp_status) {
|
||||||
|
case NTPSyncStatus.NTP_DISABLED:
|
||||||
|
return LL.NOT_ENABLED();
|
||||||
|
case NTPSyncStatus.NTP_INACTIVE:
|
||||||
|
return LL.INACTIVE(0);
|
||||||
|
case NTPSyncStatus.NTP_ACTIVE:
|
||||||
|
return LL.ACTIVE();
|
||||||
|
default:
|
||||||
|
return LL.UNKNOWN();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ntpStatusHighlight = () => {
|
||||||
|
switch (data.ntp_status) {
|
||||||
|
case NTPSyncStatus.NTP_DISABLED:
|
||||||
|
return theme.palette.info.main;
|
||||||
|
case NTPSyncStatus.NTP_INACTIVE:
|
||||||
|
return theme.palette.error.main;
|
||||||
|
case NTPSyncStatus.NTP_ACTIVE:
|
||||||
|
return theme.palette.success.main;
|
||||||
|
default:
|
||||||
|
return theme.palette.error.main;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeHighlight = (value: boolean) => (value ? theme.palette.success.main : theme.palette.info.main);
|
||||||
|
|
||||||
|
const scan = async () => {
|
||||||
|
await scanDevices()
|
||||||
|
.then(() => {
|
||||||
|
toast.info(LL.SCANNING() + '...');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(err.message);
|
||||||
|
});
|
||||||
|
setConfirmScan(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderScanDialog = () => (
|
||||||
|
<Dialog sx={dialogStyle} open={confirmScan} onClose={() => setConfirmScan(false)}>
|
||||||
|
<DialogTitle>{LL.SCAN_DEVICES()}</DialogTitle>
|
||||||
|
<DialogContent dividers>{LL.EMS_SCAN()}</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button startIcon={<CancelIcon />} variant="outlined" onClick={() => setConfirmScan(false)} color="secondary">
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button startIcon={<PermScanWifiIcon />} variant="outlined" onClick={scan} color="primary">
|
||||||
|
{LL.SCAN()}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
|
const content = () => {
|
||||||
|
if (!data) {
|
||||||
|
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: busStatusHighlight(), color: 'white' }}>
|
||||||
|
<DirectionsBusIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.EMS_BUS_STATUS()} secondary={busStatus()} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={TimerIcon}
|
||||||
|
bgcolor="#c5572c"
|
||||||
|
label={LL.UPTIME()}
|
||||||
|
text={formatDurationSec(data.uptime)}
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListItem>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5d89f7', color: 'white' }}>
|
||||||
|
<DeviceHubIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText
|
||||||
|
primary={LL.ACTIVE_DEVICES()}
|
||||||
|
secondary={
|
||||||
|
LL.NUM_DEVICES({ num: data.num_devices }) +
|
||||||
|
', ' +
|
||||||
|
LL.NUM_TEMP_SENSORS({ num: data.num_sensors }) +
|
||||||
|
', ' +
|
||||||
|
LL.NUM_ANALOG_SENSORS({ num: data.num_analogs })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{me.admin && (
|
||||||
|
<Button
|
||||||
|
startIcon={<PermScanWifiIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => setConfirmScan(true)}
|
||||||
|
>
|
||||||
|
{LL.SCAN_DEVICES()}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</ListItem>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={BuildIcon}
|
||||||
|
bgcolor="#134ba2"
|
||||||
|
label={LL.EMS_ESP_VER()}
|
||||||
|
text={data.emsesp_version}
|
||||||
|
to="/settings/upload"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
{/* TODO: translate */}
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={MemoryIcon}
|
||||||
|
bgcolor="#68374d"
|
||||||
|
label="System Memory"
|
||||||
|
text={formatNumber(data.free_heap) + ' KB'}
|
||||||
|
to="/settings/espsystemstatus"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={DeviceHubIcon}
|
||||||
|
bgcolor={activeHighlight(data.mqtt_status)}
|
||||||
|
label={LL.STATUS_OF('MQTT')}
|
||||||
|
text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)}
|
||||||
|
to="/settings/mqtt/status"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={AccessTimeIcon}
|
||||||
|
bgcolor={ntpStatusHighlight()}
|
||||||
|
label={LL.STATUS_OF('NTP')}
|
||||||
|
text={ntpStatus()}
|
||||||
|
to="/settings/ntp/status"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={CastIcon}
|
||||||
|
bgcolor={activeHighlight(data.ota_status)}
|
||||||
|
label={LL.STATUS_OF('OTA')}
|
||||||
|
text={data.ota_status ? LL.ACTIVE() : LL.INACTIVE(0)}
|
||||||
|
to="/settings/ota"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
|
||||||
|
<ListMenuItem
|
||||||
|
disabled={!me.admin}
|
||||||
|
icon={SettingsInputAntennaIcon}
|
||||||
|
bgcolor={activeHighlight(data.ota_status)}
|
||||||
|
label={LL.ACCESS_POINT(0)}
|
||||||
|
text={data.ap_status ? LL.ACTIVE() : LL.INACTIVE(0)}
|
||||||
|
to="/settings/ap/status"
|
||||||
|
/>
|
||||||
|
<Divider variant="inset" component="li" />
|
||||||
|
</List>
|
||||||
|
|
||||||
|
{renderScanDialog()}
|
||||||
|
|
||||||
|
<Box mt={2} display="flex" flexWrap="wrap">
|
||||||
|
<Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={loadData}>
|
||||||
|
{LL.REFRESH()}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <SectionContent>{content()}</SectionContent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SystemStatus;
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
import AppsIcon from '@mui/icons-material/Apps';
|
|
||||||
import BuildIcon from '@mui/icons-material/Build';
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
|
||||||
import DevicesIcon from '@mui/icons-material/Devices';
|
|
||||||
import FolderIcon from '@mui/icons-material/Folder';
|
|
||||||
import MemoryIcon from '@mui/icons-material/Memory';
|
|
||||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
||||||
import SdCardAlertIcon from '@mui/icons-material/SdCardAlert';
|
|
||||||
import SdStorageIcon from '@mui/icons-material/SdStorage';
|
|
||||||
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
|
|
||||||
import ShowChartIcon from '@mui/icons-material/ShowChart';
|
|
||||||
import TimerIcon from '@mui/icons-material/Timer';
|
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
DialogTitle,
|
|
||||||
Divider,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemAvatar,
|
|
||||||
ListItemText
|
|
||||||
} from '@mui/material';
|
|
||||||
|
|
||||||
import { useRequest } from 'alova';
|
|
||||||
import { useContext, useState } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
import { FeaturesContext } from '../../contexts/features';
|
|
||||||
import RestartMonitor from './RestartMonitor';
|
|
||||||
import SystemStatusVersionDialog from './SystemStatusVersionDialog';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
import { dialogStyle } from 'CustomTheme';
|
|
||||||
import * as SystemApi from 'api/system';
|
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
|
|
||||||
function formatNumber(num: number) {
|
|
||||||
return new Intl.NumberFormat().format(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
const SystemStatusForm: FC = () => {
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
|
|
||||||
const { me } = useContext(AuthenticatedContext);
|
|
||||||
const [confirmRestart, setConfirmRestart] = useState<boolean>(false);
|
|
||||||
const [confirmFactoryReset, setConfirmFactoryReset] = useState<boolean>(false);
|
|
||||||
const [processing, setProcessing] = useState<boolean>(false);
|
|
||||||
const [restarting, setRestarting] = useState<boolean>();
|
|
||||||
const [versionDialogOpen, setVersionDialogOpen] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const { features } = useContext(FeaturesContext);
|
|
||||||
|
|
||||||
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { send: factoryResetCommand } = useRequest(SystemApi.factoryReset(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { send: partitionCommand } = useRequest(SystemApi.partition(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus, { force: true });
|
|
||||||
|
|
||||||
const restart = async () => {
|
|
||||||
setProcessing(true);
|
|
||||||
await restartCommand()
|
|
||||||
.then(() => {
|
|
||||||
setRestarting(true);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
toast.error(err.message);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setConfirmRestart(false);
|
|
||||||
setProcessing(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const factoryReset = async () => {
|
|
||||||
setProcessing(true);
|
|
||||||
await factoryResetCommand()
|
|
||||||
.then(() => {
|
|
||||||
setRestarting(true);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
toast.error(err.message);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setConfirmFactoryReset(false);
|
|
||||||
setProcessing(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const partition = async () => {
|
|
||||||
setProcessing(true);
|
|
||||||
await partitionCommand()
|
|
||||||
.then(() => {
|
|
||||||
setRestarting(true);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
toast.error(err.message);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setConfirmRestart(false);
|
|
||||||
setProcessing(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderRestartDialog = () => (
|
|
||||||
<Dialog sx={dialogStyle} open={confirmRestart} onClose={() => setConfirmRestart(false)}>
|
|
||||||
<DialogTitle>{LL.RESTART()}</DialogTitle>
|
|
||||||
<DialogContent dividers>{LL.RESTART_CONFIRM()}</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button
|
|
||||||
startIcon={<CancelIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setConfirmRestart(false)}
|
|
||||||
disabled={processing}
|
|
||||||
color="secondary"
|
|
||||||
>
|
|
||||||
{LL.CANCEL()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<PowerSettingsNewIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={restart}
|
|
||||||
disabled={processing}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{LL.RESTART()}
|
|
||||||
</Button>
|
|
||||||
{data?.has_loader && (
|
|
||||||
<Button
|
|
||||||
startIcon={<PowerSettingsNewIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={partition}
|
|
||||||
disabled={processing}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
EMS-ESP-Loader
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderFactoryResetDialog = () => (
|
|
||||||
<Dialog sx={dialogStyle} open={confirmFactoryReset} onClose={() => setConfirmFactoryReset(false)}>
|
|
||||||
<DialogTitle>{LL.FACTORY_RESET()}</DialogTitle>
|
|
||||||
<DialogContent dividers>{LL.SYSTEM_FACTORY_TEXT_DIALOG()}</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button
|
|
||||||
startIcon={<CancelIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setConfirmFactoryReset(false)}
|
|
||||||
disabled={processing}
|
|
||||||
color="secondary"
|
|
||||||
>
|
|
||||||
{LL.CANCEL()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<SettingsBackupRestoreIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={factoryReset}
|
|
||||||
disabled={processing}
|
|
||||||
color="error"
|
|
||||||
>
|
|
||||||
{LL.FACTORY_RESET()}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = () => {
|
|
||||||
if (!data) {
|
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<List>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<BuildIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText primary={LL.EMS_ESP_VER()} secondary={data.emsesp_version} />
|
|
||||||
<Button color="primary" onClick={() => setVersionDialogOpen(true)}>
|
|
||||||
{LL.VERSION_CHECK(0)}
|
|
||||||
</Button>
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<DevicesIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText primary={LL.PLATFORM()} secondary={data.esp_platform + ' / ' + data.sdk_version} />
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<TimerIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText primary={LL.UPTIME()} secondary={data.uptime} />
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<ShowChartIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText primary={LL.CPU_FREQ()} secondary={data.cpu_freq_mhz + ' MHz'} />
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<MemoryIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={LL.HEAP()}
|
|
||||||
secondary={formatNumber(data.free_heap) + ' KB / ' + formatNumber(data.max_alloc_heap) + ' KB '}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
{data.psram_size !== undefined && data.free_psram !== undefined && (
|
|
||||||
<>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<AppsIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={LL.PSRAM()}
|
|
||||||
secondary={formatNumber(data.psram_size) + ' KB / ' + formatNumber(data.free_psram) + ' KB'}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<SdStorageIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={LL.FLASH()}
|
|
||||||
secondary={
|
|
||||||
formatNumber(data.flash_chip_size) + ' KB / ' + (data.flash_chip_speed / 1000000).toFixed(0) + ' MHz'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<SdCardAlertIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={LL.APPSIZE()}
|
|
||||||
secondary={formatNumber(data.app_used) + ' KB / ' + formatNumber(data.app_free) + ' KB'}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<FolderIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={LL.FILESYSTEM()}
|
|
||||||
secondary={formatNumber(data.fs_used) + ' KB / ' + formatNumber(data.fs_free) + ' KB'}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<Divider variant="inset" component="li" />
|
|
||||||
</List>
|
|
||||||
<Box display="flex" flexWrap="wrap">
|
|
||||||
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
|
|
||||||
<ButtonRow>
|
|
||||||
<Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={loadData}>
|
|
||||||
{LL.REFRESH()}
|
|
||||||
</Button>
|
|
||||||
</ButtonRow>
|
|
||||||
</Box>
|
|
||||||
{me.admin && (
|
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
|
||||||
<ButtonRow>
|
|
||||||
<Button
|
|
||||||
startIcon={<PowerSettingsNewIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => setConfirmRestart(true)}
|
|
||||||
>
|
|
||||||
{LL.RESTART()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<SettingsBackupRestoreIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setConfirmFactoryReset(true)}
|
|
||||||
color="error"
|
|
||||||
>
|
|
||||||
{LL.FACTORY_RESET()}
|
|
||||||
</Button>
|
|
||||||
</ButtonRow>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
{renderRestartDialog()}
|
|
||||||
{renderFactoryResetDialog()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SectionContent title={LL.STATUS_OF(LL.SYSTEM(1))} titleGutter>
|
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
|
||||||
{data && (
|
|
||||||
<SystemStatusVersionDialog
|
|
||||||
open={versionDialogOpen}
|
|
||||||
onClose={() => setVersionDialogOpen(false)}
|
|
||||||
version={data.emsesp_version}
|
|
||||||
platform={features.platform}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SystemStatusForm;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, Typography } from '@mui/material';
|
|
||||||
import { useRequest } from 'alova';
|
|
||||||
import { useCallback, useEffect } from 'react';
|
|
||||||
import { dialogStyle } from 'CustomTheme';
|
|
||||||
import * as SystemApi from 'api/system';
|
|
||||||
|
|
||||||
import MessageBox from 'components/MessageBox';
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
|
|
||||||
type SystemStatusVersionDialogProps = {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
version: string;
|
|
||||||
platform: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SystemStatusVersionDialog = ({ open, onClose, version, platform }: SystemStatusVersionDialogProps) => {
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
const { send: getLatestVersion, data: latestVersion } = useRequest(SystemApi.getStableVersion, {
|
|
||||||
immediate: false,
|
|
||||||
force: true
|
|
||||||
});
|
|
||||||
const { send: getLatestDevVersion, data: latestDevVersion } = useRequest(SystemApi.getDevVersion, {
|
|
||||||
immediate: false,
|
|
||||||
force: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
|
|
||||||
const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/';
|
|
||||||
|
|
||||||
const STABLE_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md';
|
|
||||||
const DEV_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
|
|
||||||
|
|
||||||
const uploadURL = window.location.origin + '/system/upload';
|
|
||||||
|
|
||||||
const connected = latestVersion && latestDevVersion;
|
|
||||||
|
|
||||||
const getVersions = useCallback(async () => {
|
|
||||||
await getLatestVersion();
|
|
||||||
await getLatestDevVersion();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (open) {
|
|
||||||
void getVersions();
|
|
||||||
}
|
|
||||||
}, [getVersions, open]);
|
|
||||||
|
|
||||||
const getBinURL = (v: string) => 'EMS-ESP-' + v.replaceAll('.', '_') + '-' + platform.replaceAll('-', '_') + '.bin';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog sx={dialogStyle} open={open} onClose={onClose}>
|
|
||||||
<DialogTitle>{LL.VERSION_CHECK(1)}</DialogTitle>
|
|
||||||
<DialogContent dividers>
|
|
||||||
<MessageBox my={0} level="info" message={LL.VERSION_ON() + ' ' + version + ' (' + platform + ')'} />
|
|
||||||
{latestVersion && (
|
|
||||||
<Box mt={2} mb={2}>
|
|
||||||
{LL.THE_LATEST()} <b>{LL.OFFICIAL()}</b> {LL.RELEASE_IS()} <b>{latestVersion}</b>
|
|
||||||
(
|
|
||||||
<Link target="_blank" href={STABLE_RELNOTES_URL} color="primary">
|
|
||||||
{LL.RELEASE_NOTES()}
|
|
||||||
</Link>
|
|
||||||
) (
|
|
||||||
<Link
|
|
||||||
target="_blank"
|
|
||||||
href={STABLE_URL + 'v' + latestVersion + '/' + getBinURL(latestVersion)}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{LL.DOWNLOAD(1)}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{latestDevVersion && (
|
|
||||||
<Box mt={2} mb={2}>
|
|
||||||
{LL.THE_LATEST()} <b>{LL.DEVELOPMENT()}</b> {LL.RELEASE_IS()}
|
|
||||||
<b>{latestDevVersion}</b>
|
|
||||||
(
|
|
||||||
<Link target="_blank" href={DEV_RELNOTES_URL} color="primary">
|
|
||||||
{LL.RELEASE_NOTES()}
|
|
||||||
</Link>
|
|
||||||
) (
|
|
||||||
<Link target="_blank" href={DEV_URL + getBinURL(latestDevVersion)} color="primary">
|
|
||||||
{LL.DOWNLOAD(1)}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{connected && (
|
|
||||||
<Box color="warning.main" mt={2}>
|
|
||||||
<Typography variant="body2">
|
|
||||||
{LL.USE()}
|
|
||||||
<Link href={uploadURL} color="primary">
|
|
||||||
{LL.UPLOAD()}
|
|
||||||
</Link>
|
|
||||||
{LL.SYSTEM_APPLY_FIRMWARE()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{!connected && <MessageBox my={2} level="warning" message="No internet connection" />}
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button variant="outlined" onClick={onClose} color="secondary">
|
|
||||||
{LL.CLOSE()}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SystemStatusVersionDialog;
|
|
||||||
308
interface/src/framework/system/UploadDownload.tsx
Normal file
308
interface/src/framework/system/UploadDownload.tsx
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
|
import { Typography, Button, Box, Link } from '@mui/material';
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import { useState, type FC } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import RestartMonitor from './RestartMonitor';
|
||||||
|
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
|
import { FormLoader, SectionContent, SingleUpload, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import * as EMSESP from 'project/api';
|
||||||
|
|
||||||
|
const UploadDownload: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
const [restarting, setRestarting] = useState<boolean>();
|
||||||
|
const [md5, setMd5] = useState<string>();
|
||||||
|
|
||||||
|
const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
const { send: getCustomizations, onSuccess: onSuccessGetCustomizations } = useRequest(EMSESP.getCustomizations(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
const { send: getEntities, onSuccess: onSuccessGetEntities } = useRequest(EMSESP.getEntities(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
const { send: getSchedule, onSuccess: onSuccessGetSchedule } = useRequest(EMSESP.getSchedule(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
const { send: getAPI, onSuccess: onGetAPI } = useRequest((data) => EMSESP.API(data), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: data, send: loadData, error } = useRequest(SystemApi.readESPSystemStatus, { force: true });
|
||||||
|
|
||||||
|
const { data: latestVersion } = useRequest(SystemApi.getStableVersion, {
|
||||||
|
immediate: true,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: latestDevVersion } = useRequest(SystemApi.getDevVersion, {
|
||||||
|
immediate: true,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
|
||||||
|
const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/';
|
||||||
|
|
||||||
|
const STABLE_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md';
|
||||||
|
const DEV_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
|
||||||
|
|
||||||
|
const getBinURL = (v: string) =>
|
||||||
|
'EMS-ESP-' + v.replaceAll('.', '_') + '-' + data.esp_platform.replaceAll('-', '_') + '.bin';
|
||||||
|
|
||||||
|
const {
|
||||||
|
loading: isUploading,
|
||||||
|
uploading: progress,
|
||||||
|
send: sendUpload,
|
||||||
|
onSuccess: onSuccessUpload,
|
||||||
|
abort: cancelUpload
|
||||||
|
} = useRequest(SystemApi.uploadFile, {
|
||||||
|
immediate: false,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
|
||||||
|
onSuccessUpload(({ data }: any) => {
|
||||||
|
if (data) {
|
||||||
|
setMd5(data.md5);
|
||||||
|
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
|
||||||
|
} else {
|
||||||
|
setRestarting(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const startUpload = async (files: File[]) => {
|
||||||
|
await sendUpload(files[0]).catch((err) => {
|
||||||
|
if (err.message === 'The user aborted a request') {
|
||||||
|
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
|
||||||
|
} else if (err.message === 'Network Error') {
|
||||||
|
toast.warning('Invalid file extension or incompatible bin file');
|
||||||
|
} else {
|
||||||
|
toast.error(err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveFile = (json: any, endpoint: string) => {
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = URL.createObjectURL(
|
||||||
|
new Blob([JSON.stringify(json, null, 2)], {
|
||||||
|
type: 'text/plain'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
anchor.download = 'emsesp_' + endpoint;
|
||||||
|
anchor.click();
|
||||||
|
URL.revokeObjectURL(anchor.href);
|
||||||
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
|
};
|
||||||
|
|
||||||
|
onSuccessGetSettings((event) => {
|
||||||
|
saveFile(event.data, 'settings.json');
|
||||||
|
});
|
||||||
|
onSuccessGetCustomizations((event) => {
|
||||||
|
saveFile(event.data, 'customizations.json');
|
||||||
|
});
|
||||||
|
onSuccessGetEntities((event) => {
|
||||||
|
saveFile(event.data, 'entities.json');
|
||||||
|
});
|
||||||
|
onSuccessGetSchedule((event) => {
|
||||||
|
saveFile(event.data, 'schedule.json');
|
||||||
|
});
|
||||||
|
onGetAPI((event) => {
|
||||||
|
saveFile(event.data, event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt');
|
||||||
|
});
|
||||||
|
|
||||||
|
const downloadSettings = async () => {
|
||||||
|
await getSettings().catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadCustomizations = async () => {
|
||||||
|
await getCustomizations().catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadEntities = async () => {
|
||||||
|
await getEntities().catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadSchedule = async () => {
|
||||||
|
await getSchedule()
|
||||||
|
.catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const callAPI = async (device: string, entity: string) => {
|
||||||
|
await getAPI({ device, entity, id: 0 }).catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useLayoutTitle(LL.UPLOAD_DOWNLOAD());
|
||||||
|
|
||||||
|
const content = () => {
|
||||||
|
if (!data) {
|
||||||
|
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
||||||
|
{LL.EMS_ESP_VER()}
|
||||||
|
</Typography>
|
||||||
|
<Box p={2} border="2px solid grey" borderRadius={2}>
|
||||||
|
{LL.VERSION_ON() + ' '}
|
||||||
|
<b>{data.emsesp_version}</b> ({data.esp_platform})
|
||||||
|
{latestVersion && (
|
||||||
|
<Box mt={2}>
|
||||||
|
{LL.THE_LATEST()} {LL.OFFICIAL()} {LL.RELEASE_IS()} <b>{latestVersion}</b>
|
||||||
|
(
|
||||||
|
<Link target="_blank" href={STABLE_RELNOTES_URL} color="primary">
|
||||||
|
{LL.RELEASE_NOTES()}
|
||||||
|
</Link>
|
||||||
|
) (
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
href={STABLE_URL + 'v' + latestVersion + '/' + getBinURL(latestVersion)}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{LL.DOWNLOAD(1)}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{latestDevVersion && (
|
||||||
|
<Box mt={2}>
|
||||||
|
{LL.THE_LATEST()} {LL.DEVELOPMENT()} {LL.RELEASE_IS()}
|
||||||
|
<b>{latestDevVersion}</b>
|
||||||
|
(
|
||||||
|
<Link target="_blank" href={DEV_RELNOTES_URL} color="primary">
|
||||||
|
{LL.RELEASE_NOTES()}
|
||||||
|
</Link>
|
||||||
|
) (
|
||||||
|
<Link target="_blank" href={DEV_URL + getBinURL(latestDevVersion)} color="primary">
|
||||||
|
{LL.DOWNLOAD(1)}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
|
{LL.UPLOAD()}
|
||||||
|
</Typography>
|
||||||
|
<Box mb={2} color="warning.main">
|
||||||
|
<Typography variant="body2">
|
||||||
|
{LL.UPLOAD_TEXT()}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{LL.RESTART_TEXT(1)}.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{md5 && (
|
||||||
|
<Box mb={2}>
|
||||||
|
<Typography variant="body2">{'MD5: ' + md5}</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<SingleUpload onDrop={startUpload} onCancel={cancelUpload} isUploading={isUploading} progress={progress} />
|
||||||
|
{!isUploading && (
|
||||||
|
<>
|
||||||
|
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
|
||||||
|
{LL.DOWNLOAD(0)}
|
||||||
|
</Typography>
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mb={1} variant="body2">
|
||||||
|
{LL.HELP_INFORMATION_4()}
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => callAPI('system', 'info')}
|
||||||
|
>
|
||||||
|
{LL.SUPPORT_INFORMATION(0)}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => callAPI('system', 'allvalues')}
|
||||||
|
>
|
||||||
|
All Values
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
|
{LL.DOWNLOAD_SETTINGS_TEXT()}
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={downloadSettings}
|
||||||
|
>
|
||||||
|
{LL.SETTINGS_OF('')}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
|
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={downloadCustomizations}
|
||||||
|
>
|
||||||
|
{LL.CUSTOMIZATIONS()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={downloadEntities}
|
||||||
|
>
|
||||||
|
{LL.CUSTOM_ENTITIES(0)}
|
||||||
|
</Button>
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
|
{LL.DOWNLOAD_SCHEDULE_TEXT()}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={downloadSchedule}
|
||||||
|
>
|
||||||
|
{LL.SCHEDULE(0)}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <SectionContent>{restarting ? <RestartMonitor /> : content()}</SectionContent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UploadDownload;
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
|
||||||
import { Typography, Button, Box } from '@mui/material';
|
|
||||||
import { useRequest } from 'alova';
|
|
||||||
import { useState, type FC } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
import RestartMonitor from './RestartMonitor';
|
|
||||||
|
|
||||||
import * as SystemApi from 'api/system';
|
|
||||||
import { SectionContent, SingleUpload } from 'components';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
import * as EMSESP from 'project/api';
|
|
||||||
|
|
||||||
const UploadFileForm: FC = () => {
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
const [restarting, setRestarting] = useState<boolean>(false);
|
|
||||||
const [md5, setMd5] = useState<string>();
|
|
||||||
|
|
||||||
const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest(EMSESP.getSettings(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
const { send: getCustomizations, onSuccess: onSuccessgetCustomizations } = useRequest(EMSESP.getCustomizations(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
const { send: getEntities, onSuccess: onSuccessGetEntities } = useRequest(EMSESP.getEntities(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
const { send: getSchedule, onSuccess: onSuccessGetSchedule } = useRequest(EMSESP.getSchedule(), {
|
|
||||||
immediate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
loading: isUploading,
|
|
||||||
uploading: progress,
|
|
||||||
send: sendUpload,
|
|
||||||
onSuccess: onSuccessUpload,
|
|
||||||
abort: cancelUpload
|
|
||||||
} = useRequest(SystemApi.uploadFile, {
|
|
||||||
immediate: false,
|
|
||||||
force: true
|
|
||||||
});
|
|
||||||
|
|
||||||
onSuccessUpload(({ data }: any) => {
|
|
||||||
if (data) {
|
|
||||||
setMd5(data.md5);
|
|
||||||
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
|
|
||||||
} else {
|
|
||||||
setRestarting(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const startUpload = async (files: File[]) => {
|
|
||||||
await sendUpload(files[0]).catch((err) => {
|
|
||||||
if (err.message === 'The user aborted a request') {
|
|
||||||
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
|
|
||||||
} else if (err.message === 'Network Error') {
|
|
||||||
toast.warning('Invalid file extension or incompatible bin file');
|
|
||||||
} else {
|
|
||||||
toast.error(err.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveFile = (json: any, endpoint: string) => {
|
|
||||||
const anchor = document.createElement('a');
|
|
||||||
anchor.href = URL.createObjectURL(
|
|
||||||
new Blob([JSON.stringify(json, null, 2)], {
|
|
||||||
type: 'text/plain'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
anchor.download = 'emsesp_' + endpoint + '.json';
|
|
||||||
anchor.click();
|
|
||||||
URL.revokeObjectURL(anchor.href);
|
|
||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
|
||||||
};
|
|
||||||
|
|
||||||
onSuccessGetSettings((event) => {
|
|
||||||
saveFile(event.data, 'settings');
|
|
||||||
});
|
|
||||||
onSuccessgetCustomizations((event) => {
|
|
||||||
saveFile(event.data, 'customizations');
|
|
||||||
});
|
|
||||||
onSuccessGetEntities((event) => {
|
|
||||||
saveFile(event.data, 'entities');
|
|
||||||
});
|
|
||||||
onSuccessGetSchedule((event) => {
|
|
||||||
saveFile(event.data, 'schedule');
|
|
||||||
});
|
|
||||||
|
|
||||||
const downloadSettings = async () => {
|
|
||||||
await getSettings().catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadCustomizations = async () => {
|
|
||||||
await getCustomizations().catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadEntities = async () => {
|
|
||||||
await getEntities().catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadSchedule = async () => {
|
|
||||||
await getSchedule().catch((error) => {
|
|
||||||
toast.error(error.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const content = () => (
|
|
||||||
<>
|
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
|
||||||
{LL.UPLOAD()}
|
|
||||||
</Typography>
|
|
||||||
<Box mb={2} color="warning.main">
|
|
||||||
<Typography variant="body2">{LL.UPLOAD_TEXT()} </Typography>
|
|
||||||
</Box>
|
|
||||||
{md5 && (
|
|
||||||
<Box mb={2}>
|
|
||||||
<Typography variant="body2">{'MD5: ' + md5}</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<SingleUpload onDrop={startUpload} onCancel={cancelUpload} isUploading={isUploading} progress={progress} />
|
|
||||||
{!isUploading && (
|
|
||||||
<>
|
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
|
||||||
{LL.DOWNLOAD(0)}
|
|
||||||
</Typography>
|
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography mb={1} variant="body2">
|
|
||||||
{LL.DOWNLOAD_SETTINGS_TEXT()}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSettings}>
|
|
||||||
{LL.SETTINGS_OF('')}
|
|
||||||
</Button>
|
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography mt={2} mb={1} variant="body2">
|
|
||||||
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}{' '}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadCustomizations}>
|
|
||||||
{LL.CUSTOMIZATIONS()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
sx={{ ml: 2 }}
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={downloadEntities}
|
|
||||||
>
|
|
||||||
{LL.CUSTOM_ENTITIES(0)}
|
|
||||||
</Button>
|
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography mt={2} mb={1} variant="body2">
|
|
||||||
{LL.DOWNLOAD_SCHEDULE_TEXT()}{' '}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={downloadSchedule}>
|
|
||||||
{LL.SCHEDULE(0)}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<SectionContent title={LL.UPLOAD_DOWNLOAD()} titleGutter>
|
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UploadFileForm;
|
|
||||||
1
interface/src/i18n/SK.svg
Normal file
1
interface/src/i18n/SK.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 85.333 512 341.333"><path fill="#FFF" d="M0 85.337h512v341.326H0z"/><path fill="#0052B4" d="M0 196.641h512v118.717H0z"/><path fill="#D80027" d="M0 315.359h512v111.304H0z"/><path fill="#FFF" d="M129.468 181.799v85.136c0 48.429 63.267 63.267 63.267 63.267S256 315.362 256 266.935v-85.136H129.468z"/><path fill="#D80027" d="M146.126 184.294v81.941c0 5.472 1.215 10.64 3.623 15.485h85.97c2.408-4.844 3.623-10.012 3.623-15.485v-81.941h-93.216z"/><path fill="#FFF" d="M221.301 241.427h-21.425v-14.283h14.284v-14.283h-14.284v-14.284h-14.283v14.284h-14.282v14.283h14.282v14.283h-21.426v14.284h21.426v14.283h14.283v-14.283h21.425z"/><path fill="#0052B4" d="M169.232 301.658c9.204 5.783 18.66 9.143 23.502 10.636 4.842-1.494 14.298-4.852 23.502-10.636 9.282-5.833 15.79-12.506 19.484-19.939a24.878 24.878 0 0 0-14.418-4.583c-1.956 0-3.856.232-5.682.657-3.871-8.796-12.658-14.94-22.884-14.94-10.227 0-19.013 6.144-22.884 14.94a25.048 25.048 0 0 0-5.682-.657 24.88 24.88 0 0 0-14.418 4.583c3.691 7.433 10.198 14.106 19.48 19.939z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -12,7 +12,6 @@ const de: Translation = {
|
|||||||
USERNAME: 'Nutzername',
|
USERNAME: 'Nutzername',
|
||||||
PASSWORD: 'Passwort',
|
PASSWORD: 'Passwort',
|
||||||
SU_PASSWORD: 'su Passwort',
|
SU_PASSWORD: 'su Passwort',
|
||||||
DASHBOARD: 'Kontrollzentrum',
|
|
||||||
SETTINGS_OF: '{0} Einstellungen',
|
SETTINGS_OF: '{0} Einstellungen',
|
||||||
HELP_OF: '{0} Hilfe',
|
HELP_OF: '{0} Hilfe',
|
||||||
LOGGED_IN: 'Eingeloggt als {name}',
|
LOGGED_IN: 'Eingeloggt als {name}',
|
||||||
@@ -37,8 +36,6 @@ const de: Translation = {
|
|||||||
BRAND: 'Marke',
|
BRAND: 'Marke',
|
||||||
ENTITY_NAME: 'Entitätsname',
|
ENTITY_NAME: 'Entitätsname',
|
||||||
VALUE: '{{Wert|wert}}',
|
VALUE: '{{Wert|wert}}',
|
||||||
DEVICE_DATA: 'Gerätedaten',
|
|
||||||
SENSOR_DATA: 'Sensordaten',
|
|
||||||
DEVICES: 'Geräte',
|
DEVICES: 'Geräte',
|
||||||
SENSORS: 'Sensoren',
|
SENSORS: 'Sensoren',
|
||||||
RUN_COMMAND: 'Befehl ausführen',
|
RUN_COMMAND: 'Befehl ausführen',
|
||||||
@@ -83,7 +80,6 @@ const de: Translation = {
|
|||||||
FAIL: 'FEHLER',
|
FAIL: 'FEHLER',
|
||||||
QUALITY: 'QUALITÄT',
|
QUALITY: 'QUALITÄT',
|
||||||
SCAN_DEVICES: 'Nach neuen Geräten suchen',
|
SCAN_DEVICES: 'Nach neuen Geräten suchen',
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS-Bus- und Aktivitätsstatus',
|
|
||||||
SCAN: 'Suche',
|
SCAN: 'Suche',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS-Telegramme empfangen (Rx)',
|
'EMS-Telegramme empfangen (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const de: Translation = {
|
|||||||
BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen',
|
BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen',
|
||||||
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
|
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
|
||||||
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
|
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
|
||||||
|
HEATINGOFF: 'Heizen ausschalten beim EMS-ESP Start',
|
||||||
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',
|
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',
|
||||||
ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren',
|
ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren',
|
||||||
TRIGGER_TIME: 'Auslösezeit',
|
TRIGGER_TIME: 'Auslösezeit',
|
||||||
@@ -162,15 +159,12 @@ const de: Translation = {
|
|||||||
OPTIONS: 'Optionen',
|
OPTIONS: 'Optionen',
|
||||||
NAME: 'Name',
|
NAME: 'Name',
|
||||||
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?',
|
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?',
|
||||||
DEVICE_ENTITIES: 'Geräteentitäten',
|
|
||||||
SUPPORT_INFORMATION: 'Unterstützende Informationen',
|
SUPPORT_INFORMATION: 'Unterstützende Informationen',
|
||||||
CLICK_HERE: 'Hier klicken',
|
|
||||||
HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki',
|
HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki',
|
||||||
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
|
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
|
||||||
HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf Github',
|
HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf Github',
|
||||||
HELP_INFORMATION_4: 'Bitte laden Sie die System-Details und hängen Sie sie an das Support-Issue an. ',
|
HELP_INFORMATION_4: 'Bitte laden Sie die System-Details und hängen Sie sie an das Support-Issue an. ',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP ist ein freies Open-Source Projekt. Bitte unterstützen Sie die zukünftige Entwicklung mit einem "Star" auf Github!',
|
HELP_INFORMATION_5: 'EMS-ESP ist ein freies Open-Source Projekt. Bitte unterstützen Sie die zukünftige Entwicklung mit einem "Star" auf Github!',
|
||||||
SUPPORT_INFO: 'Support Info',
|
|
||||||
UPLOAD: 'Hochladen',
|
UPLOAD: 'Hochladen',
|
||||||
DOWNLOAD: '{{H|h|h}}erunterladen',
|
DOWNLOAD: '{{H|h|h}}erunterladen',
|
||||||
ABORTED: 'abgebrochen',
|
ABORTED: 'abgebrochen',
|
||||||
@@ -181,26 +175,22 @@ const de: Translation = {
|
|||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen',
|
UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen',
|
||||||
VERSION_ON: 'Sie verwenden derzeit',
|
VERSION_ON: 'Sie verwenden derzeit',
|
||||||
SYSTEM_APPLY_FIRMWARE: 'um die neue Firmware anzuwenden',
|
|
||||||
CLOSE: 'Schließen',
|
CLOSE: 'Schließen',
|
||||||
USE: 'Verwenden Sie',
|
USE: 'Verwenden Sie',
|
||||||
FACTORY_RESET: 'Werkseinstellung',
|
FACTORY_RESET: 'Werkseinstellung',
|
||||||
SYSTEM_FACTORY_TEXT: 'EMS-ESP wurde auf Werkseinstellung gesetzt und startet als Zugangspunkt neu',
|
SYSTEM_FACTORY_TEXT: 'EMS-ESP wurde auf Werkseinstellung gesetzt und startet als Zugangspunkt neu',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?',
|
||||||
VERSION_CHECK: 'Versionsprüfung',
|
|
||||||
THE_LATEST: 'Die neueste',
|
THE_LATEST: 'Die neueste',
|
||||||
OFFICIAL: 'offizielle',
|
OFFICIAL: 'offizielle',
|
||||||
DEVELOPMENT: 'Entwicklungs',
|
DEVELOPMENT: 'Entwicklungs',
|
||||||
RELEASE_IS: 'release ist', // TODO translate
|
RELEASE_IS: 'Release ist',
|
||||||
RELEASE_NOTES: 'Versionshinweise',
|
RELEASE_NOTES: 'Versionshinweise',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
PLATFORM: 'Platform (Platform / SDK)',
|
|
||||||
UPTIME: 'System Betriebszeit',
|
UPTIME: 'System Betriebszeit',
|
||||||
CPU_FREQ: 'CPU Frequenz',
|
|
||||||
HEAP: 'freier RAM Speicher (Gesamt / max. Block)',
|
HEAP: 'freier RAM Speicher (Gesamt / max. Block)',
|
||||||
PSRAM: 'PSRAM (Größe / Frei)',
|
PSRAM: 'PSRAM (Größe / Frei)',
|
||||||
FLASH: 'Flash Speicher (Größe / Geschwindigkeit)',
|
FLASH: 'Flash Speicher (Größe / Geschwindigkeit)',
|
||||||
APPSIZE: 'Programm (Genutzt / Frei)',
|
APPSIZE: 'Programm (Partition: Genutzt / Frei)',
|
||||||
FILESYSTEM: 'Dateisystem (Genutzt / Frei)',
|
FILESYSTEM: 'Dateisystem (Genutzt / Frei)',
|
||||||
BUFFER_SIZE: 'max. Puffergröße',
|
BUFFER_SIZE: 'max. Puffergröße',
|
||||||
COMPACT: 'Kompakte Darstellung',
|
COMPACT: 'Kompakte Darstellung',
|
||||||
@@ -246,6 +236,7 @@ const de: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Thermostate',
|
MQTT_INT_THERMOSTATS: 'Thermostate',
|
||||||
MQTT_INT_SOLAR: 'Solarmodule',
|
MQTT_INT_SOLAR: 'Solarmodule',
|
||||||
MQTT_INT_MIXER: 'Mischermodule',
|
MQTT_INT_MIXER: 'Mischermodule',
|
||||||
|
MQTT_INT_WATER: 'Warmwassermodule',
|
||||||
MQTT_QUEUE: 'MQTT Queue',
|
MQTT_QUEUE: 'MQTT Queue',
|
||||||
DEFAULT: 'Standard',
|
DEFAULT: 'Standard',
|
||||||
MQTT_ENTITY_FORMAT: 'Entitäts-ID Format',
|
MQTT_ENTITY_FORMAT: 'Entitäts-ID Format',
|
||||||
@@ -282,6 +273,7 @@ const de: Translation = {
|
|||||||
NETWORK_SCANNER: 'Netzwerk Suche',
|
NETWORK_SCANNER: 'Netzwerk Suche',
|
||||||
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
||||||
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren',
|
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren',
|
||||||
|
NETWORK_BLANK_BSSID: 'Freilassen um nur SSID für die Verbindung zu nutzen',
|
||||||
TX_POWER: 'Tx Leistung',
|
TX_POWER: 'Tx Leistung',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
||||||
@@ -308,7 +300,7 @@ const de: Translation = {
|
|||||||
LEAVE: 'Verlassen',
|
LEAVE: 'Verlassen',
|
||||||
SCHEDULER: 'Planer',
|
SCHEDULER: 'Planer',
|
||||||
SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern',
|
SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern',
|
||||||
SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
|
SCHEDULER_HELP_2: '00:00 aktiviert einmalige Ausführung am Start',
|
||||||
SCHEDULE: 'Zeitplan',
|
SCHEDULE: 'Zeitplan',
|
||||||
TIME: 'Zeit',
|
TIME: 'Zeit',
|
||||||
TIMER: 'Timer',
|
TIMER: 'Timer',
|
||||||
@@ -317,12 +309,22 @@ const de: Translation = {
|
|||||||
SCHEDULE_TIMER_2: 'jede Minute',
|
SCHEDULE_TIMER_2: 'jede Minute',
|
||||||
SCHEDULE_TIMER_3: 'jede Stunde',
|
SCHEDULE_TIMER_3: 'jede Stunde',
|
||||||
CUSTOM_ENTITIES: 'Individuelle Entitäten',
|
CUSTOM_ENTITIES: 'Individuelle Entitäten',
|
||||||
ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus',
|
ENTITIES_HELP_1: 'Definition eigener EMS-Werte oder dynamischer Variablen',
|
||||||
ENTITIES_UPDATED: 'Entitäten gespeichert',
|
ENTITIES_UPDATED: 'Entitäten gespeichert',
|
||||||
WRITEABLE: 'Schreibbar',
|
WRITEABLE: 'Schreibbar',
|
||||||
SHOWING: 'Anzeigen von',
|
SHOWING: 'Anzeigen von',
|
||||||
SEARCH: 'Suche',
|
SEARCH: 'Suche',
|
||||||
CERT: 'TSL Zertifikat (Freilassen um TSL zu deaktivieren)'
|
CERT: 'TLS Zertifikat (Freilassen für unsichere Verbindung)',
|
||||||
|
ENABLE_TLS: 'Aktiviere TLS',
|
||||||
|
ON: 'An',
|
||||||
|
OFF: 'Aus',
|
||||||
|
POLARITY: 'Polarität',
|
||||||
|
ACTIVEHIGH: 'Aktiv Positiv',
|
||||||
|
ACTIVELOW: 'Aktiv Negativ',
|
||||||
|
UNCHANGED: 'Unverändert',
|
||||||
|
ALWAYS: 'Immer',
|
||||||
|
ACTIVITY: 'Activity', // TODO translate
|
||||||
|
CONFIGURE: 'Configure {0}' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const en: Translation = {
|
|||||||
USERNAME: 'Username',
|
USERNAME: 'Username',
|
||||||
PASSWORD: 'Password',
|
PASSWORD: 'Password',
|
||||||
SU_PASSWORD: 'su Password',
|
SU_PASSWORD: 'su Password',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Settings',
|
SETTINGS_OF: '{0} Settings',
|
||||||
HELP_OF: '{0} Help',
|
HELP_OF: '{0} Help',
|
||||||
LOGGED_IN: 'Logged in as {name}',
|
LOGGED_IN: 'Logged in as {name}',
|
||||||
@@ -37,8 +36,6 @@ const en: Translation = {
|
|||||||
BRAND: 'Brand',
|
BRAND: 'Brand',
|
||||||
ENTITY_NAME: 'Entity Name',
|
ENTITY_NAME: 'Entity Name',
|
||||||
VALUE: '{{Value|value}}',
|
VALUE: '{{Value|value}}',
|
||||||
DEVICE_DATA: 'Device Data',
|
|
||||||
SENSOR_DATA: 'Sensor Data',
|
|
||||||
DEVICES: 'Devices',
|
DEVICES: 'Devices',
|
||||||
SENSORS: 'Sensors',
|
SENSORS: 'Sensors',
|
||||||
RUN_COMMAND: 'Call Command',
|
RUN_COMMAND: 'Call Command',
|
||||||
@@ -63,7 +60,7 @@ const en: Translation = {
|
|||||||
FREQ: 'Frequency',
|
FREQ: 'Frequency',
|
||||||
DUTY_CYCLE: 'Duty Cycle',
|
DUTY_CYCLE: 'Duty Cycle',
|
||||||
UNIT: 'UoM',
|
UNIT: 'UoM',
|
||||||
STARTVALUE: 'Start value',
|
STARTVALUE: 'Start Value',
|
||||||
WARN_GPIO: 'Warning: be careful when assigning a GPIO!',
|
WARN_GPIO: 'Warning: be careful when assigning a GPIO!',
|
||||||
EDIT: 'Edit',
|
EDIT: 'Edit',
|
||||||
SENSOR: 'Sensor',
|
SENSOR: 'Sensor',
|
||||||
@@ -83,7 +80,6 @@ const en: Translation = {
|
|||||||
FAIL: 'FAIL',
|
FAIL: 'FAIL',
|
||||||
QUALITY: 'QUALITY',
|
QUALITY: 'QUALITY',
|
||||||
SCAN_DEVICES: 'Scan for new devices',
|
SCAN_DEVICES: 'Scan for new devices',
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS Bus & Activity Status',
|
|
||||||
SCAN: 'Scan',
|
SCAN: 'Scan',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS Telegrams Received (Rx)',
|
'EMS Telegrams Received (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const en: Translation = {
|
|||||||
BYPASS_TOKEN: 'Bypass Access Token authorization on API calls',
|
BYPASS_TOKEN: 'Bypass Access Token authorization on API calls',
|
||||||
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
|
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
|
||||||
UNDERCLOCK_CPU: 'Underclock CPU speed',
|
UNDERCLOCK_CPU: 'Underclock CPU speed',
|
||||||
|
HEATINGOFF: 'Start boiler with forced heating off',
|
||||||
ENABLE_SHOWER_TIMER: 'Enable Shower Timer',
|
ENABLE_SHOWER_TIMER: 'Enable Shower Timer',
|
||||||
ENABLE_SHOWER_ALERT: 'Enable Shower Alert',
|
ENABLE_SHOWER_ALERT: 'Enable Shower Alert',
|
||||||
TRIGGER_TIME: 'Trigger Time',
|
TRIGGER_TIME: 'Trigger Time',
|
||||||
@@ -157,20 +154,17 @@ const en: Translation = {
|
|||||||
CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API',
|
CUSTOMIZATIONS_HELP_4: 'exclude from MQTT and API',
|
||||||
CUSTOMIZATIONS_HELP_5: 'hide from Dashboard',
|
CUSTOMIZATIONS_HELP_5: 'hide from Dashboard',
|
||||||
CUSTOMIZATIONS_HELP_6: 'remove from memory',
|
CUSTOMIZATIONS_HELP_6: 'remove from memory',
|
||||||
SELECT_DEVICE: 'Select a device',
|
SELECT_DEVICE: 'select a device',
|
||||||
SET_ALL: 'set all',
|
SET_ALL: 'set all',
|
||||||
OPTIONS: 'Options',
|
OPTIONS: 'Options',
|
||||||
NAME: 'Name',
|
NAME: 'Name',
|
||||||
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?',
|
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?',
|
||||||
DEVICE_ENTITIES: 'Device Entities',
|
|
||||||
SUPPORT_INFORMATION: 'Support Information',
|
SUPPORT_INFORMATION: 'Support Information',
|
||||||
CLICK_HERE: 'Click Here',
|
|
||||||
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'For live community chat join our Discord server',
|
HELP_INFORMATION_2: 'For live community chat join our Discord server',
|
||||||
HELP_INFORMATION_3: 'To request a feature or report a bug',
|
HELP_INFORMATION_3: 'To request a feature or report a bug',
|
||||||
HELP_INFORMATION_4: 'remember to download and attach your system information for a faster response when reporting an issue',
|
HELP_INFORMATION_4: 'Download and attach your support information for a faster response when reporting an issue',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!',
|
HELP_INFORMATION_5: 'EMS-ESP is a free and open-source project. Please support its future development by giving it a star on Github!',
|
||||||
SUPPORT_INFO: 'Support Info',
|
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'aborted',
|
ABORTED: 'aborted',
|
||||||
@@ -181,26 +175,22 @@ const en: Translation = {
|
|||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Upload/Download',
|
UPLOAD_DOWNLOAD: 'Upload/Download',
|
||||||
VERSION_ON: 'You are currently on version',
|
VERSION_ON: 'You are currently on version',
|
||||||
SYSTEM_APPLY_FIRMWARE: 'to apply the new firmware',
|
|
||||||
CLOSE: 'Close',
|
CLOSE: 'Close',
|
||||||
USE: 'Use',
|
USE: 'Use',
|
||||||
FACTORY_RESET: 'Factory Reset',
|
FACTORY_RESET: 'Factory Reset',
|
||||||
SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart',
|
SYSTEM_FACTORY_TEXT: 'Device has been factory reset and will now restart',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?',
|
||||||
VERSION_CHECK: 'Version Check',
|
|
||||||
THE_LATEST: 'The latest',
|
THE_LATEST: 'The latest',
|
||||||
OFFICIAL: 'official',
|
OFFICIAL: 'official',
|
||||||
DEVELOPMENT: 'development',
|
DEVELOPMENT: 'development',
|
||||||
RELEASE_IS: 'release is',
|
RELEASE_IS: 'release is',
|
||||||
RELEASE_NOTES: 'release notes',
|
RELEASE_NOTES: 'release notes',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
PLATFORM: 'Device (Platform / SDK)',
|
|
||||||
UPTIME: 'System Uptime',
|
UPTIME: 'System Uptime',
|
||||||
CPU_FREQ: 'CPU Frequency',
|
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Application (Used / Free)',
|
APPSIZE: 'Application (Partition: Used / Free)',
|
||||||
FILESYSTEM: 'File System (Used / Free)',
|
FILESYSTEM: 'File System (Used / Free)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -230,7 +220,7 @@ const en: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Optional',
|
OPTIONAL: 'optional',
|
||||||
FORMATTING: 'Formatting',
|
FORMATTING: 'Formatting',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nested in a single topic',
|
MQTT_NEST_1: 'Nested in a single topic',
|
||||||
@@ -246,6 +236,7 @@ const en: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Thermostats',
|
MQTT_INT_THERMOSTATS: 'Thermostats',
|
||||||
MQTT_INT_SOLAR: 'Solar Modules',
|
MQTT_INT_SOLAR: 'Solar Modules',
|
||||||
MQTT_INT_MIXER: 'Mixer Modules',
|
MQTT_INT_MIXER: 'Mixer Modules',
|
||||||
|
MQTT_INT_WATER: 'Water Modules',
|
||||||
MQTT_QUEUE: 'MQTT Queue',
|
MQTT_QUEUE: 'MQTT Queue',
|
||||||
DEFAULT: 'Default',
|
DEFAULT: 'Default',
|
||||||
MQTT_ENTITY_FORMAT: 'Entity ID format',
|
MQTT_ENTITY_FORMAT: 'Entity ID format',
|
||||||
@@ -282,6 +273,7 @@ const en: Translation = {
|
|||||||
NETWORK_SCANNER: 'Network Scanner',
|
NETWORK_SCANNER: 'Network Scanner',
|
||||||
NETWORK_NO_WIFI: 'No WiFi networks found',
|
NETWORK_NO_WIFI: 'No WiFi networks found',
|
||||||
NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH',
|
NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH',
|
||||||
|
NETWORK_BLANK_BSSID: 'leave blank to use only SSID',
|
||||||
TX_POWER: 'Tx Power',
|
TX_POWER: 'Tx Power',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
||||||
@@ -317,12 +309,22 @@ const en: Translation = {
|
|||||||
SCHEDULE_TIMER_2: 'every minute',
|
SCHEDULE_TIMER_2: 'every minute',
|
||||||
SCHEDULE_TIMER_3: 'every hour',
|
SCHEDULE_TIMER_3: 'every hour',
|
||||||
CUSTOM_ENTITIES: 'Custom Entities',
|
CUSTOM_ENTITIES: 'Custom Entities',
|
||||||
ENTITIES_HELP_1: 'Fetch custom entities from the EMS bus',
|
ENTITIES_HELP_1: 'Define custom EMS entities or dynamic user variables',
|
||||||
ENTITIES_UPDATED: 'Entities Updated',
|
ENTITIES_UPDATED: 'Entities Updated',
|
||||||
WRITEABLE: 'Writeable',
|
WRITEABLE: 'Writeable',
|
||||||
SHOWING: 'Showing',
|
SHOWING: 'Showing',
|
||||||
SEARCH: 'Search',
|
SEARCH: 'Search',
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)'
|
CERT: 'TLS root certificate (leave blank for insecure)',
|
||||||
|
ENABLE_TLS: 'Enable TLS',
|
||||||
|
ON: 'On',
|
||||||
|
OFF: 'Off',
|
||||||
|
POLARITY: 'Polarity',
|
||||||
|
ACTIVEHIGH: 'Active High',
|
||||||
|
ACTIVELOW: 'Active Low',
|
||||||
|
UNCHANGED: 'Unchanged',
|
||||||
|
ALWAYS: 'Always',
|
||||||
|
ACTIVITY: 'Activity',
|
||||||
|
CONFIGURE: 'Configure {0}'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const fr: Translation = {
|
|||||||
USERNAME: 'Nom d\'utilisateur',
|
USERNAME: 'Nom d\'utilisateur',
|
||||||
PASSWORD: 'Mot de passe',
|
PASSWORD: 'Mot de passe',
|
||||||
SU_PASSWORD: 'Mot de passe su',
|
SU_PASSWORD: 'Mot de passe su',
|
||||||
DASHBOARD: 'Tableau de bord',
|
|
||||||
SETTINGS_OF: 'Paramètres {0}',
|
SETTINGS_OF: 'Paramètres {0}',
|
||||||
HELP_OF: 'Aide {0}',
|
HELP_OF: 'Aide {0}',
|
||||||
LOGGED_IN: 'Connecté en tant que {name}',
|
LOGGED_IN: 'Connecté en tant que {name}',
|
||||||
@@ -37,8 +36,6 @@ const fr: Translation = {
|
|||||||
BRAND: 'Marque',
|
BRAND: 'Marque',
|
||||||
ENTITY_NAME: 'Nom de l\'entité',
|
ENTITY_NAME: 'Nom de l\'entité',
|
||||||
VALUE: 'Valeur',
|
VALUE: 'Valeur',
|
||||||
DEVICE_DATA: 'Données des appareils',
|
|
||||||
SENSOR_DATA: 'Données des capteurs',
|
|
||||||
DEVICES: 'Appareils',
|
DEVICES: 'Appareils',
|
||||||
SENSORS: 'Capteurs',
|
SENSORS: 'Capteurs',
|
||||||
RUN_COMMAND: 'Lancer une commande',
|
RUN_COMMAND: 'Lancer une commande',
|
||||||
@@ -83,7 +80,6 @@ const fr: Translation = {
|
|||||||
FAIL: 'ÉCHEC',
|
FAIL: 'ÉCHEC',
|
||||||
QUALITY: 'QUALITÉ',
|
QUALITY: 'QUALITÉ',
|
||||||
SCAN_DEVICES: 'Rechercher de nouveaux appareils',
|
SCAN_DEVICES: 'Rechercher de nouveaux appareils',
|
||||||
EMS_BUS_STATUS_TITLE: 'Statut du bus et de l\'activité EMS',
|
|
||||||
SCAN: 'Scan',
|
SCAN: 'Scan',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'Télégrammes EMS reçus (Rx)',
|
'Télégrammes EMS reçus (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const fr: Translation = {
|
|||||||
BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API',
|
BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API',
|
||||||
READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)',
|
READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)',
|
||||||
UNDERCLOCK_CPU: 'Underclock du CPU',
|
UNDERCLOCK_CPU: 'Underclock du CPU',
|
||||||
|
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
||||||
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
|
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
|
||||||
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
|
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
|
||||||
TRIGGER_TIME: 'Durée avant déclenchement',
|
TRIGGER_TIME: 'Durée avant déclenchement',
|
||||||
@@ -162,15 +159,12 @@ const fr: Translation = {
|
|||||||
OPTIONS: 'Options',
|
OPTIONS: 'Options',
|
||||||
NAME: 'Nom',
|
NAME: 'Nom',
|
||||||
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations, y compris les paramètres personnalisés des capteurs de température et analogiques ?',
|
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations, y compris les paramètres personnalisés des capteurs de température et analogiques ?',
|
||||||
DEVICE_ENTITIES: 'Entités de l\'appareil',
|
|
||||||
SUPPORT_INFORMATION: 'Information de support',
|
SUPPORT_INFORMATION: 'Information de support',
|
||||||
CLICK_HERE: 'Cliquez ici',
|
|
||||||
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
||||||
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
|
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
|
||||||
HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème',
|
HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème',
|
||||||
HELP_INFORMATION_4: 'n\'oubliez pas de télécharger et de joindre les informations relatives à votre système pour obtenir une réponse plus rapide lorsque vous signalez un problème',
|
HELP_INFORMATION_4: 'N\'oubliez pas de télécharger et de joindre les informations relatives à votre système pour obtenir une réponse plus rapide lorsque vous signalez un problème',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP est un projet libre et open-source. Merci de soutenir son développement futur en lui donnant une étoile sur Github !',
|
HELP_INFORMATION_5: 'EMS-ESP est un projet libre et open-source. Merci de soutenir son développement futur en lui donnant une étoile sur Github !',
|
||||||
SUPPORT_INFO: 'Information de support',
|
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'annulé',
|
ABORTED: 'annulé',
|
||||||
@@ -181,26 +175,22 @@ const fr: Translation = {
|
|||||||
STATUS_OF: 'Statut {0}',
|
STATUS_OF: 'Statut {0}',
|
||||||
UPLOAD_DOWNLOAD: 'Upload/Download',
|
UPLOAD_DOWNLOAD: 'Upload/Download',
|
||||||
VERSION_ON: 'You are currently on', // TODO translate
|
VERSION_ON: 'You are currently on', // TODO translate
|
||||||
SYSTEM_APPLY_FIRMWARE: 'pour appliquer le nouveau firmware',
|
|
||||||
CLOSE: 'Fermer',
|
CLOSE: 'Fermer',
|
||||||
USE: 'Utiliser',
|
USE: 'Utiliser',
|
||||||
FACTORY_RESET: 'Réinitialisation',
|
FACTORY_RESET: 'Réinitialisation',
|
||||||
SYSTEM_FACTORY_TEXT: 'L\'appareil a été réinitialisé et va maintenant redémarrer',
|
SYSTEM_FACTORY_TEXT: 'L\'appareil a été réinitialisé et va maintenant redémarrer',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Êtes-vous sûr de vouloir réinitialiser l\'appareil à ses paramètres d\'usine ?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Êtes-vous sûr de vouloir réinitialiser l\'appareil à ses paramètres d\'usine ?',
|
||||||
VERSION_CHECK: 'Vérification de la version',
|
|
||||||
THE_LATEST: 'La dernière',
|
THE_LATEST: 'La dernière',
|
||||||
OFFICIAL: 'officielle',
|
OFFICIAL: 'officielle',
|
||||||
DEVELOPMENT: 'développement',
|
DEVELOPMENT: 'développement',
|
||||||
RELEASE_IS: 'release est', // TODO translate
|
RELEASE_IS: 'release est', // TODO translate
|
||||||
RELEASE_NOTES: 'notes de version',
|
RELEASE_NOTES: 'notes de version',
|
||||||
EMS_ESP_VER: 'Version EMS-ESP',
|
EMS_ESP_VER: 'Version EMS-ESP',
|
||||||
PLATFORM: 'Appareil (Plateforme / SDK)',
|
|
||||||
UPTIME: 'Durée de fonctionnement du système',
|
UPTIME: 'Durée de fonctionnement du système',
|
||||||
CPU_FREQ: 'Fréquence du CPU',
|
|
||||||
HEAP: 'Heap (Libre / Max Allouée)',
|
HEAP: 'Heap (Libre / Max Allouée)',
|
||||||
PSRAM: 'PSRAM (Taille / Libre)',
|
PSRAM: 'PSRAM (Taille / Libre)',
|
||||||
FLASH: 'Flash Chip (Taille / Vitesse)',
|
FLASH: 'Flash Chip (Taille / Vitesse)',
|
||||||
APPSIZE: 'Application (Utilisée / Libre)',
|
APPSIZE: 'Application (Partition: Utilisée / Libre)',
|
||||||
FILESYSTEM: 'File System (Utilisée / Libre)',
|
FILESYSTEM: 'File System (Utilisée / Libre)',
|
||||||
BUFFER_SIZE: 'Max taille du buffer',
|
BUFFER_SIZE: 'Max taille du buffer',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -230,7 +220,7 @@ const fr: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Optionnel',
|
OPTIONAL: 'optionnel',
|
||||||
FORMATTING: 'Mise en forme',
|
FORMATTING: 'Mise en forme',
|
||||||
MQTT_FORMAT: 'Format du Topic/Payload',
|
MQTT_FORMAT: 'Format du Topic/Payload',
|
||||||
MQTT_NEST_1: 'Englobé dans un topic unique',
|
MQTT_NEST_1: 'Englobé dans un topic unique',
|
||||||
@@ -246,6 +236,7 @@ const fr: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Thermostats',
|
MQTT_INT_THERMOSTATS: 'Thermostats',
|
||||||
MQTT_INT_SOLAR: 'Modules solaires',
|
MQTT_INT_SOLAR: 'Modules solaires',
|
||||||
MQTT_INT_MIXER: 'Modules mélangeurs',
|
MQTT_INT_MIXER: 'Modules mélangeurs',
|
||||||
|
MQTT_INT_WATER: 'Modules eau',
|
||||||
MQTT_QUEUE: 'Queue MQTT',
|
MQTT_QUEUE: 'Queue MQTT',
|
||||||
DEFAULT: 'Défaut',
|
DEFAULT: 'Défaut',
|
||||||
MQTT_ENTITY_FORMAT: 'Entity ID format', // TODO translate
|
MQTT_ENTITY_FORMAT: 'Entity ID format', // TODO translate
|
||||||
@@ -282,6 +273,7 @@ const fr: Translation = {
|
|||||||
NETWORK_SCANNER: 'Scan réseau',
|
NETWORK_SCANNER: 'Scan réseau',
|
||||||
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
||||||
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate
|
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate
|
||||||
|
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
||||||
TX_POWER: 'Puissance Tx',
|
TX_POWER: 'Puissance Tx',
|
||||||
HOSTNAME: 'Nom d\'hôte',
|
HOSTNAME: 'Nom d\'hôte',
|
||||||
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
||||||
@@ -322,7 +314,17 @@ const fr: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
||||||
|
ENABLE_TLS: 'Activer TLS',
|
||||||
|
ON: 'On', // TODO translate
|
||||||
|
OFF: 'Off', // TODO translate
|
||||||
|
POLARITY: 'Polarity', // TODO translate
|
||||||
|
ACTIVEHIGH: 'Active High', // TODO translate
|
||||||
|
ACTIVELOW: 'Active Low', // TODO translate
|
||||||
|
UNCHANGED: 'Unchanged', // TODO translate
|
||||||
|
ALWAYS: 'Always', // TODO translate
|
||||||
|
ACTIVITY: 'Activity', // TODO translate
|
||||||
|
CONFIGURE: 'Configure {0}' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const it: Translation = {
|
|||||||
USERNAME: 'Nome Utente',
|
USERNAME: 'Nome Utente',
|
||||||
PASSWORD: 'Password',
|
PASSWORD: 'Password',
|
||||||
SU_PASSWORD: 'su Password',
|
SU_PASSWORD: 'su Password',
|
||||||
DASHBOARD: 'Pannello di Controllo',
|
|
||||||
SETTINGS_OF: 'Impostazioni {0}',
|
SETTINGS_OF: 'Impostazioni {0}',
|
||||||
HELP_OF: '{0} Aiuto',
|
HELP_OF: '{0} Aiuto',
|
||||||
LOGGED_IN: 'Registrato come {name}',
|
LOGGED_IN: 'Registrato come {name}',
|
||||||
@@ -37,8 +36,6 @@ const it: Translation = {
|
|||||||
BRAND: 'Marca',
|
BRAND: 'Marca',
|
||||||
ENTITY_NAME: 'Nome Entità',
|
ENTITY_NAME: 'Nome Entità',
|
||||||
VALUE: '{{Valore|valore}}',
|
VALUE: '{{Valore|valore}}',
|
||||||
DEVICE_DATA: 'Device Data',
|
|
||||||
SENSOR_DATA: 'Sensor Data',
|
|
||||||
DEVICES: 'Dispositivi',
|
DEVICES: 'Dispositivi',
|
||||||
SENSORS: 'Sensori',
|
SENSORS: 'Sensori',
|
||||||
RUN_COMMAND: 'Esegui',
|
RUN_COMMAND: 'Esegui',
|
||||||
@@ -51,7 +48,6 @@ const it: Translation = {
|
|||||||
REMOVE: 'Elimina',
|
REMOVE: 'Elimina',
|
||||||
PROBLEM_UPDATING: 'Problema aggiornamento',
|
PROBLEM_UPDATING: 'Problema aggiornamento',
|
||||||
PROBLEM_LOADING: 'Problema caricamento',
|
PROBLEM_LOADING: 'Problema caricamento',
|
||||||
ACCESS_DENIED: 'Accesso Negato',
|
|
||||||
ANALOG_SENSOR: 'Sensore Analogico',
|
ANALOG_SENSOR: 'Sensore Analogico',
|
||||||
ANALOG_SENSORS: 'Sensori Analogici',
|
ANALOG_SENSORS: 'Sensori Analogici',
|
||||||
SETTINGS: 'Settings',
|
SETTINGS: 'Settings',
|
||||||
@@ -71,7 +67,6 @@ const it: Translation = {
|
|||||||
TEMP_SENSOR: 'Sensore Temperatura',
|
TEMP_SENSOR: 'Sensore Temperatura',
|
||||||
TEMP_SENSORS: 'Sensori Temperatura',
|
TEMP_SENSORS: 'Sensori Temperatura',
|
||||||
WRITE_CMD_SENT: 'Scrittura comando inviata',
|
WRITE_CMD_SENT: 'Scrittura comando inviata',
|
||||||
WRITE_CMD_FAILED: 'Scittura comando fallita',
|
|
||||||
EMS_BUS_WARNING: 'EMS bus disconnesso. Se questo avvertimento persiste dopo alcuni secondi prego verificare impostazioni scheda',
|
EMS_BUS_WARNING: 'EMS bus disconnesso. Se questo avvertimento persiste dopo alcuni secondi prego verificare impostazioni scheda',
|
||||||
EMS_BUS_SCANNING: 'Scansione dispositivi EMS ...',
|
EMS_BUS_SCANNING: 'Scansione dispositivi EMS ...',
|
||||||
CONNECTED: 'Connesso',
|
CONNECTED: 'Connesso',
|
||||||
@@ -85,7 +80,6 @@ const it: Translation = {
|
|||||||
FAIL: 'FALLITO',
|
FAIL: 'FALLITO',
|
||||||
QUALITY: 'QUALITÂ',
|
QUALITY: 'QUALITÂ',
|
||||||
SCAN_DEVICES: 'Scansione per nuovi dispositivi',
|
SCAN_DEVICES: 'Scansione per nuovi dispositivi',
|
||||||
EMS_BUS_STATUS_TITLE: 'Bus EMS & Stato Attività',
|
|
||||||
SCAN: 'Scansione',
|
SCAN: 'Scansione',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'Telegrammi EMS Ricevuti (Rx)',
|
'Telegrammi EMS Ricevuti (Rx)',
|
||||||
@@ -128,6 +122,7 @@ const it: Translation = {
|
|||||||
BYPASS_TOKEN: 'Ignora autorizzazione del token di accesso sulle chiamate API',
|
BYPASS_TOKEN: 'Ignora autorizzazione del token di accesso sulle chiamate API',
|
||||||
READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)',
|
READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)',
|
||||||
UNDERCLOCK_CPU: 'Abbassa velocità della CPU',
|
UNDERCLOCK_CPU: 'Abbassa velocità della CPU',
|
||||||
|
HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento',
|
||||||
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
||||||
ENABLE_SHOWER_ALERT: 'Abilita avviso doccia',
|
ENABLE_SHOWER_ALERT: 'Abilita avviso doccia',
|
||||||
TRIGGER_TIME: 'Tempo di avvio',
|
TRIGGER_TIME: 'Tempo di avvio',
|
||||||
@@ -164,15 +159,12 @@ const it: Translation = {
|
|||||||
OPTIONS: 'Opzioni',
|
OPTIONS: 'Opzioni',
|
||||||
NAME: 'Nome',
|
NAME: 'Nome',
|
||||||
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni incluse le impostazioni personalizzate dei sensori di temperatura e analogici?',
|
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni incluse le impostazioni personalizzate dei sensori di temperatura e analogici?',
|
||||||
DEVICE_ENTITIES: 'Entità Dispositivo',
|
|
||||||
SUPPORT_INFORMATION: 'Informazioni di Supporto',
|
SUPPORT_INFORMATION: 'Informazioni di Supporto',
|
||||||
CLICK_HERE: 'Clicca qui',
|
|
||||||
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
|
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
|
||||||
HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore',
|
HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore',
|
||||||
HELP_INFORMATION_4: 'ricordati di scaricare e allegare le informazioni del tuo sistema per una risposta più rapida quando segnali un problema',
|
HELP_INFORMATION_4: 'Ricordati di scaricare e allegare le informazioni del tuo sistema per una risposta più rapida quando segnali un problema',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP è un progetto gratuito e open-source. Supporta il suo sviluppo futuro assegnandogli una stella su Github!',
|
HELP_INFORMATION_5: 'EMS-ESP è un progetto gratuito e open-source. Supporta il suo sviluppo futuro assegnandogli una stella su Github!',
|
||||||
SUPPORT_INFO: 'Info Supporto',
|
|
||||||
UPLOAD: 'Carica',
|
UPLOAD: 'Carica',
|
||||||
DOWNLOAD: 'Scarica',
|
DOWNLOAD: 'Scarica',
|
||||||
ABORTED: 'Annullato',
|
ABORTED: 'Annullato',
|
||||||
@@ -183,26 +175,22 @@ const it: Translation = {
|
|||||||
STATUS_OF: 'Stato {0}',
|
STATUS_OF: 'Stato {0}',
|
||||||
UPLOAD_DOWNLOAD: 'Caricamento/Scaricamento',
|
UPLOAD_DOWNLOAD: 'Caricamento/Scaricamento',
|
||||||
VERSION_ON: 'Attualmente stai eseguendo la versione',
|
VERSION_ON: 'Attualmente stai eseguendo la versione',
|
||||||
SYSTEM_APPLY_FIRMWARE: 'per applicare il nuovo firmware',
|
|
||||||
CLOSE: 'Chiudere',
|
CLOSE: 'Chiudere',
|
||||||
USE: 'Usa',
|
USE: 'Usa',
|
||||||
FACTORY_RESET: 'Impostazioni di fabbrica',
|
FACTORY_RESET: 'Impostazioni di fabbrica',
|
||||||
SYSTEM_FACTORY_TEXT: 'Il dispositivo è stato ripristinato alle impostazioni di fabbrica e ora verrà riavviato',
|
SYSTEM_FACTORY_TEXT: 'Il dispositivo è stato ripristinato alle impostazioni di fabbrica e ora verrà riavviato',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??',
|
||||||
VERSION_CHECK: 'Verifica Versione',
|
|
||||||
THE_LATEST: 'Ultima',
|
THE_LATEST: 'Ultima',
|
||||||
OFFICIAL: 'ufficiale',
|
OFFICIAL: 'ufficiale',
|
||||||
DEVELOPMENT: 'sviluppo',
|
DEVELOPMENT: 'sviluppo',
|
||||||
RELEASE_IS: 'rilascio é',
|
RELEASE_IS: 'rilascio é',
|
||||||
RELEASE_NOTES: 'note rilascio',
|
RELEASE_NOTES: 'note rilascio',
|
||||||
EMS_ESP_VER: 'Versione EMS-ESP',
|
EMS_ESP_VER: 'Versione EMS-ESP',
|
||||||
PLATFORM: 'Dispositivo (Piattaforma / SDK)',
|
|
||||||
UPTIME: 'Tempo di attività del sistema',
|
UPTIME: 'Tempo di attività del sistema',
|
||||||
CPU_FREQ: 'Frequenza CPU ',
|
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Applicazione (Usata / Libera)',
|
APPSIZE: 'Applicazione (Partizione: Usata / Libera)',
|
||||||
FILESYSTEM: 'Memoria Sistema (Usata / Libera)',
|
FILESYSTEM: 'Memoria Sistema (Usata / Libera)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -232,7 +220,7 @@ const it: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Cliente',
|
CLIENT: 'Cliente',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Opzionale',
|
OPTIONAL: 'opzionale',
|
||||||
FORMATTING: 'Formattazione',
|
FORMATTING: 'Formattazione',
|
||||||
MQTT_FORMAT: 'Formato Topic/Payload ',
|
MQTT_FORMAT: 'Formato Topic/Payload ',
|
||||||
MQTT_NEST_1: 'Inserito in un singolo argomento',
|
MQTT_NEST_1: 'Inserito in un singolo argomento',
|
||||||
@@ -248,6 +236,7 @@ const it: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Termostati',
|
MQTT_INT_THERMOSTATS: 'Termostati',
|
||||||
MQTT_INT_SOLAR: 'Moduli solari',
|
MQTT_INT_SOLAR: 'Moduli solari',
|
||||||
MQTT_INT_MIXER: 'Moduli Mixer',
|
MQTT_INT_MIXER: 'Moduli Mixer',
|
||||||
|
MQTT_INT_WATER: 'Moduli Acqua',
|
||||||
MQTT_QUEUE: 'Coda MQTT',
|
MQTT_QUEUE: 'Coda MQTT',
|
||||||
DEFAULT: 'Predefinito',
|
DEFAULT: 'Predefinito',
|
||||||
MQTT_ENTITY_FORMAT: 'Formato ID entità',
|
MQTT_ENTITY_FORMAT: 'Formato ID entità',
|
||||||
@@ -284,6 +273,7 @@ const it: Translation = {
|
|||||||
NETWORK_SCANNER: 'Scansione Rete',
|
NETWORK_SCANNER: 'Scansione Rete',
|
||||||
NETWORK_NO_WIFI: 'Nessuana rete WiFi trovata',
|
NETWORK_NO_WIFI: 'Nessuana rete WiFi trovata',
|
||||||
NETWORK_BLANK_SSID: 'lasciare vuoto per disattivare WiFi',
|
NETWORK_BLANK_SSID: 'lasciare vuoto per disattivare WiFi',
|
||||||
|
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
||||||
TX_POWER: 'Potenza Tx',
|
TX_POWER: 'Potenza Tx',
|
||||||
HOSTNAME: 'Nome ospite',
|
HOSTNAME: 'Nome ospite',
|
||||||
NETWORK_DISABLE_SLEEP: 'Disabilita la modalità sospensione Wi-Fi',
|
NETWORK_DISABLE_SLEEP: 'Disabilita la modalità sospensione Wi-Fi',
|
||||||
@@ -319,12 +309,22 @@ const it: Translation = {
|
|||||||
SCHEDULE_TIMER_2: 'Ogni minuto',
|
SCHEDULE_TIMER_2: 'Ogni minuto',
|
||||||
SCHEDULE_TIMER_3: 'Ogni ora',
|
SCHEDULE_TIMER_3: 'Ogni ora',
|
||||||
CUSTOM_ENTITIES: 'Entità personalizzate',
|
CUSTOM_ENTITIES: 'Entità personalizzate',
|
||||||
ENTITIES_HELP_1: 'Recupera entità personalizzate dal BUS EMS',
|
ENTITIES_HELP_1: 'Recupera entità personalizzate dal BUS EMS', // TODO translate
|
||||||
ENTITIES_UPDATED: 'Entità aggiornate',
|
ENTITIES_UPDATED: 'Entità aggiornate',
|
||||||
WRITEABLE: 'Scrivibile',
|
WRITEABLE: 'Scrivibile',
|
||||||
SHOWING: 'Visualizza',
|
SHOWING: 'Visualizza',
|
||||||
SEARCH: 'Ricerca',
|
SEARCH: 'Ricerca',
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
||||||
|
ENABLE_TLS: 'Abilita TLS',
|
||||||
|
ON: 'On', // TODO translate
|
||||||
|
OFF: 'Off', // TODO translate
|
||||||
|
POLARITY: 'Polarity', // TODO translate
|
||||||
|
ACTIVEHIGH: 'Active High', // TODO translate
|
||||||
|
ACTIVELOW: 'Active Low', // TODO translate
|
||||||
|
UNCHANGED: 'Unchanged', // TODO translate
|
||||||
|
ALWAYS: 'Always', // TODO translate
|
||||||
|
ACTIVITY: 'Activity', // TODO translate
|
||||||
|
CONFIGURE: 'Configure {0}' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const nl: Translation = {
|
|||||||
USERNAME: 'Gebruikersnaam',
|
USERNAME: 'Gebruikersnaam',
|
||||||
PASSWORD: 'Wachtwoord',
|
PASSWORD: 'Wachtwoord',
|
||||||
SU_PASSWORD: 'su Wachtwoord',
|
SU_PASSWORD: 'su Wachtwoord',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Instellingen',
|
SETTINGS_OF: '{0} Instellingen',
|
||||||
HELP_OF: '{0} Help',
|
HELP_OF: '{0} Help',
|
||||||
LOGGED_IN: 'Ingelogd als {name}',
|
LOGGED_IN: 'Ingelogd als {name}',
|
||||||
@@ -37,8 +36,6 @@ const nl: Translation = {
|
|||||||
BRAND: 'Merk',
|
BRAND: 'Merk',
|
||||||
ENTITY_NAME: 'Entiteit',
|
ENTITY_NAME: 'Entiteit',
|
||||||
VALUE: '{{Waarde|waarde}}',
|
VALUE: '{{Waarde|waarde}}',
|
||||||
SENSOR_DATA: 'Sensor data',
|
|
||||||
DEVICE_DATA: 'Apparaat data',
|
|
||||||
DEVICES: 'Apparaten',
|
DEVICES: 'Apparaten',
|
||||||
SENSORS: 'Sensoren',
|
SENSORS: 'Sensoren',
|
||||||
RUN_COMMAND: 'Call commando',
|
RUN_COMMAND: 'Call commando',
|
||||||
@@ -83,7 +80,6 @@ const nl: Translation = {
|
|||||||
FAIL: 'MISLUKT',
|
FAIL: 'MISLUKT',
|
||||||
QUALITY: 'QUALITEIT',
|
QUALITY: 'QUALITEIT',
|
||||||
SCAN_DEVICES: 'Scannen naar nieuwe apparaten',
|
SCAN_DEVICES: 'Scannen naar nieuwe apparaten',
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS Bus & Activiteitenstatus',
|
|
||||||
SCAN: 'Scan',
|
SCAN: 'Scan',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS Telegrammen ontvangen (Rx)',
|
'EMS Telegrammen ontvangen (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const nl: Translation = {
|
|||||||
BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen',
|
BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen',
|
||||||
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
|
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
|
||||||
UNDERCLOCK_CPU: 'Underclock CPU snelheid',
|
UNDERCLOCK_CPU: 'Underclock CPU snelheid',
|
||||||
|
HEATINGOFF: 'Start ketel met geforceerde verwarming uit',
|
||||||
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
||||||
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
||||||
TRIGGER_TIME: 'Trigger tijd',
|
TRIGGER_TIME: 'Trigger tijd',
|
||||||
@@ -162,15 +159,12 @@ const nl: Translation = {
|
|||||||
OPTIONS: 'Opties',
|
OPTIONS: 'Opties',
|
||||||
NAME: 'Naam',
|
NAME: 'Naam',
|
||||||
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?',
|
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?',
|
||||||
DEVICE_ENTITIES: 'Apparaat Entiteiten',
|
|
||||||
SUPPORT_INFORMATION: 'Support Informatie',
|
SUPPORT_INFORMATION: 'Support Informatie',
|
||||||
CLICK_HERE: 'Klik Hier',
|
|
||||||
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
||||||
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
|
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
|
||||||
HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren',
|
HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren',
|
||||||
HELP_INFORMATION_4: 'zorg dat je ook je systeem details zijn toevoeged voor een sneller antwoord',
|
HELP_INFORMATION_4: 'Zorg dat je ook je systeem details zijn toevoeged voor een sneller antwoord',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP is een gratis en open source project. Steun ons met een Star op Github!',
|
HELP_INFORMATION_5: 'EMS-ESP is een gratis en open source project. Steun ons met een Star op Github!',
|
||||||
SUPPORT_INFO: 'Support Info',
|
|
||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
ABORTED: 'afgebroken',
|
ABORTED: 'afgebroken',
|
||||||
@@ -181,26 +175,22 @@ const nl: Translation = {
|
|||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Upload/Download',
|
UPLOAD_DOWNLOAD: 'Upload/Download',
|
||||||
VERSION_ON: 'U bevindt zich momenteel op versie',
|
VERSION_ON: 'U bevindt zich momenteel op versie',
|
||||||
SYSTEM_APPLY_FIRMWARE: 'om de nieuwe firmware te activeren',
|
|
||||||
CLOSE: 'Sluiten',
|
CLOSE: 'Sluiten',
|
||||||
USE: 'Gebruik',
|
USE: 'Gebruik',
|
||||||
FACTORY_RESET: 'Fabrieksinstellingen',
|
FACTORY_RESET: 'Fabrieksinstellingen',
|
||||||
SYSTEM_FACTORY_TEXT: 'Gateway is gereset en start nu weer op met fabrieksinstellingen',
|
SYSTEM_FACTORY_TEXT: 'Gateway is gereset en start nu weer op met fabrieksinstellingen',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?',
|
||||||
VERSION_CHECK: 'Versie Check',
|
|
||||||
THE_LATEST: 'De laatste',
|
THE_LATEST: 'De laatste',
|
||||||
OFFICIAL: 'official',
|
OFFICIAL: 'official',
|
||||||
DEVELOPMENT: 'development',
|
DEVELOPMENT: 'development',
|
||||||
RELEASE_IS: 'release is',
|
RELEASE_IS: 'release is',
|
||||||
RELEASE_NOTES: 'release notes',
|
RELEASE_NOTES: 'release notes',
|
||||||
EMS_ESP_VER: 'EMS-ESP Versie',
|
EMS_ESP_VER: 'EMS-ESP Versie',
|
||||||
PLATFORM: 'Apparaat (Platform / SDK)',
|
|
||||||
UPTIME: 'Systeem Uptime',
|
UPTIME: 'Systeem Uptime',
|
||||||
CPU_FREQ: 'CPU Frequency',
|
|
||||||
HEAP: 'Heap (Free / Max Alloc)',
|
HEAP: 'Heap (Free / Max Alloc)',
|
||||||
PSRAM: 'PSRAM (Size / Free)',
|
PSRAM: 'PSRAM (Size / Free)',
|
||||||
FLASH: 'Flash Chip (Size / Speed)',
|
FLASH: 'Flash Chip (Size / Speed)',
|
||||||
APPSIZE: 'Application (Used / Free)',
|
APPSIZE: 'Application (Partition: Used / Free)',
|
||||||
FILESYSTEM: 'File System (Used / Free)',
|
FILESYSTEM: 'File System (Used / Free)',
|
||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
@@ -230,7 +220,7 @@ const nl: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Optioneel',
|
OPTIONAL: 'optioneel',
|
||||||
FORMATTING: 'Formatteren',
|
FORMATTING: 'Formatteren',
|
||||||
MQTT_FORMAT: 'Topic/Payload Formattering',
|
MQTT_FORMAT: 'Topic/Payload Formattering',
|
||||||
MQTT_NEST_1: 'Genest in 1 topic',
|
MQTT_NEST_1: 'Genest in 1 topic',
|
||||||
@@ -246,6 +236,7 @@ const nl: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Thermostaten',
|
MQTT_INT_THERMOSTATS: 'Thermostaten',
|
||||||
MQTT_INT_SOLAR: 'Solar Modules',
|
MQTT_INT_SOLAR: 'Solar Modules',
|
||||||
MQTT_INT_MIXER: 'Mixer Modules',
|
MQTT_INT_MIXER: 'Mixer Modules',
|
||||||
|
MQTT_INT_WATER: 'Water Modules',
|
||||||
MQTT_QUEUE: 'MQTT Queue',
|
MQTT_QUEUE: 'MQTT Queue',
|
||||||
DEFAULT: 'Default',
|
DEFAULT: 'Default',
|
||||||
MQTT_ENTITY_FORMAT: 'Entity ID formaat',
|
MQTT_ENTITY_FORMAT: 'Entity ID formaat',
|
||||||
@@ -282,6 +273,7 @@ const nl: Translation = {
|
|||||||
NETWORK_SCANNER: 'Netwerk Scanner',
|
NETWORK_SCANNER: 'Netwerk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
||||||
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen',
|
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen',
|
||||||
|
NETWORK_BLANK_BSSID: 'laat leeg om alleen SSID te bebruiken',
|
||||||
TX_POWER: 'Tx Vermogen',
|
TX_POWER: 'Tx Vermogen',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
||||||
@@ -322,7 +314,17 @@ const nl: Translation = {
|
|||||||
WRITEABLE: 'Beschrijfbare',
|
WRITEABLE: 'Beschrijfbare',
|
||||||
SHOWING: 'Tonen',
|
SHOWING: 'Tonen',
|
||||||
SEARCH: 'Zoek',
|
SEARCH: 'Zoek',
|
||||||
CERT: 'TSL rootcertificaat (laat leeg om TSL uit te schakelen)'
|
CERT: 'TLS rootcertificaat (laat leeg om TLS-insecure)',
|
||||||
|
ENABLE_TLS: 'Activeer TLS',
|
||||||
|
ON: 'Aan',
|
||||||
|
OFF: 'Uit',
|
||||||
|
POLARITY: 'Polariteit',
|
||||||
|
ACTIVEHIGH: 'Actiev Hoog',
|
||||||
|
ACTIVELOW: 'Actiev Laag',
|
||||||
|
UNCHANGED: 'Ongewijzigd',
|
||||||
|
ALWAYS: 'Altijd',
|
||||||
|
ACTIVITY: 'Activiteit',
|
||||||
|
CONFIGURE: '{0} Configureren'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const no: Translation = {
|
|||||||
USERNAME: 'Brukernavn',
|
USERNAME: 'Brukernavn',
|
||||||
PASSWORD: 'Passord',
|
PASSWORD: 'Passord',
|
||||||
SU_PASSWORD: 'su Passord',
|
SU_PASSWORD: 'su Passord',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Innstillinger',
|
SETTINGS_OF: '{0} Innstillinger',
|
||||||
HELP_OF: '{0} Hjelp',
|
HELP_OF: '{0} Hjelp',
|
||||||
LOGGED_IN: 'Logget in som {name}',
|
LOGGED_IN: 'Logget in som {name}',
|
||||||
@@ -37,8 +36,6 @@ const no: Translation = {
|
|||||||
BRAND: 'Fabrikat',
|
BRAND: 'Fabrikat',
|
||||||
ENTITY_NAME: 'Objektsnavn',
|
ENTITY_NAME: 'Objektsnavn',
|
||||||
VALUE: '{{Verdi|verdi}}',
|
VALUE: '{{Verdi|verdi}}',
|
||||||
DEVICE_DATA: 'Enheterdata',
|
|
||||||
SENSOR_DATA: 'Sensordata',
|
|
||||||
DEVICES: 'Enheter',
|
DEVICES: 'Enheter',
|
||||||
SENSORS: 'Sensorer',
|
SENSORS: 'Sensorer',
|
||||||
RUN_COMMAND: 'Kjør kommando',
|
RUN_COMMAND: 'Kjør kommando',
|
||||||
@@ -83,7 +80,6 @@ const no: Translation = {
|
|||||||
FAIL: 'MISLYKKET',
|
FAIL: 'MISLYKKET',
|
||||||
QUALITY: 'KVALITET',
|
QUALITY: 'KVALITET',
|
||||||
SCAN_DEVICES: 'Søk etter nye enheter',
|
SCAN_DEVICES: 'Søk etter nye enheter',
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS Buss & Aktivitet Status',
|
|
||||||
SCAN: 'Søk',
|
SCAN: 'Søk',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS Telegrammer Mottatt (Rx)',
|
'EMS Telegrammer Mottatt (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const no: Translation = {
|
|||||||
BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall',
|
BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall',
|
||||||
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
|
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
|
||||||
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
|
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
|
||||||
|
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
||||||
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer',
|
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling',
|
ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling',
|
||||||
TRIGGER_TIME: 'Aktiveringstid',
|
TRIGGER_TIME: 'Aktiveringstid',
|
||||||
@@ -162,15 +159,12 @@ const no: Translation = {
|
|||||||
OPTIONS: 'Alternativ',
|
OPTIONS: 'Alternativ',
|
||||||
NAME: 'Navn',
|
NAME: 'Navn',
|
||||||
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger inkludert innstillinger for Temperatur og Analoge sensorer?',
|
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger inkludert innstillinger for Temperatur og Analoge sensorer?',
|
||||||
DEVICE_ENTITIES: 'Enhets objekter',
|
|
||||||
SUPPORT_INFORMATION: 'Supportinformasjon',
|
SUPPORT_INFORMATION: 'Supportinformasjon',
|
||||||
CLICK_HERE: 'Klikk her',
|
|
||||||
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
|
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
|
||||||
HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil',
|
HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil',
|
||||||
HELP_INFORMATION_4: 'husk å laste ned og legg ved din systeminformasjon for en raskere respons når du rapporterer et problem',
|
HELP_INFORMATION_4: 'Husk å laste ned og legg ved din systeminformasjon for en raskere respons når du rapporterer et problem',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP er gratis og åpen kildekode. Bidra til utviklingen ved å gi oss en stjerne på GitHub!',
|
HELP_INFORMATION_5: 'EMS-ESP er gratis og åpen kildekode. Bidra til utviklingen ved å gi oss en stjerne på GitHub!',
|
||||||
SUPPORT_INFO: 'Supportinfo',
|
|
||||||
UPLOAD: 'Opplasning',
|
UPLOAD: 'Opplasning',
|
||||||
DOWNLOAD: '{{N|n|n}}edlasting',
|
DOWNLOAD: '{{N|n|n}}edlasting',
|
||||||
ABORTED: 'avbrutt',
|
ABORTED: 'avbrutt',
|
||||||
@@ -181,26 +175,22 @@ const no: Translation = {
|
|||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Opp/Nedlasting',
|
UPLOAD_DOWNLOAD: 'Opp/Nedlasting',
|
||||||
VERSION_ON: 'You are currently on', // TODO translate
|
VERSION_ON: 'You are currently on', // TODO translate
|
||||||
SYSTEM_APPLY_FIRMWARE: 'for å aktivere ny firmware',
|
|
||||||
CLOSE: 'Steng',
|
CLOSE: 'Steng',
|
||||||
USE: 'Bruk',
|
USE: 'Bruk',
|
||||||
FACTORY_RESET: 'Sett tilbake til fabrikkinstilling',
|
FACTORY_RESET: 'Sett tilbake til fabrikkinstilling',
|
||||||
SYSTEM_FACTORY_TEXT: 'Enhet har blitt satt tilbake til fabrikkinstilling og vil restarte',
|
SYSTEM_FACTORY_TEXT: 'Enhet har blitt satt tilbake til fabrikkinstilling og vil restarte',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?',
|
||||||
VERSION_CHECK: 'Versjonsjekk',
|
|
||||||
THE_LATEST: 'Den nyeste',
|
THE_LATEST: 'Den nyeste',
|
||||||
OFFICIAL: 'official',
|
OFFICIAL: 'official',
|
||||||
DEVELOPMENT: 'development',
|
DEVELOPMENT: 'development',
|
||||||
RELEASE_IS: 'release er',
|
RELEASE_IS: 'release er',
|
||||||
RELEASE_NOTES: 'release notes',
|
RELEASE_NOTES: 'release notes',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
PLATFORM: 'Enhet (Platform / SDK)',
|
|
||||||
UPTIME: 'System Oppetid',
|
UPTIME: 'System Oppetid',
|
||||||
CPU_FREQ: 'CPU Frekvens',
|
|
||||||
HEAP: 'Heap (Ledig / Max Allokert)',
|
HEAP: 'Heap (Ledig / Max Allokert)',
|
||||||
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
||||||
FLASH: 'Flash Chip (Størrelse / Hastighet)',
|
FLASH: 'Flash Chip (Størrelse / Hastighet)',
|
||||||
APPSIZE: 'Applikasjon (Brukt / Ledig)',
|
APPSIZE: 'Applikasjon (Partition: Brukt / Ledig)',
|
||||||
FILESYSTEM: 'File System (Brukt / Ledig)',
|
FILESYSTEM: 'File System (Brukt / Ledig)',
|
||||||
BUFFER_SIZE: 'Max Buffer Størrelse',
|
BUFFER_SIZE: 'Max Buffer Størrelse',
|
||||||
COMPACT: 'Komprimere',
|
COMPACT: 'Komprimere',
|
||||||
@@ -230,7 +220,7 @@ const no: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Valgfritt',
|
OPTIONAL: 'valgfritt',
|
||||||
FORMATTING: 'Formatering',
|
FORMATTING: 'Formatering',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nestet i en topic',
|
MQTT_NEST_1: 'Nestet i en topic',
|
||||||
@@ -246,6 +236,7 @@ const no: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Termostat',
|
MQTT_INT_THERMOSTATS: 'Termostat',
|
||||||
MQTT_INT_SOLAR: 'Solpaneler',
|
MQTT_INT_SOLAR: 'Solpaneler',
|
||||||
MQTT_INT_MIXER: 'Blandeventil',
|
MQTT_INT_MIXER: 'Blandeventil',
|
||||||
|
MQTT_INT_WATER: 'Water Modules', // TODO translate
|
||||||
MQTT_QUEUE: 'MQTT Queue',
|
MQTT_QUEUE: 'MQTT Queue',
|
||||||
DEFAULT: 'Standard',
|
DEFAULT: 'Standard',
|
||||||
MQTT_ENTITY_FORMAT: 'Enhets ID format',
|
MQTT_ENTITY_FORMAT: 'Enhets ID format',
|
||||||
@@ -282,6 +273,7 @@ const no: Translation = {
|
|||||||
NETWORK_SCANNER: 'Nettverk Scanner',
|
NETWORK_SCANNER: 'Nettverk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
||||||
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // TODO translate
|
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // TODO translate
|
||||||
|
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
||||||
@@ -322,7 +314,17 @@ const no: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
||||||
|
ENABLE_TLS: 'Aktiviser TLS',
|
||||||
|
ON: 'On', // TODO translate
|
||||||
|
OFF: 'Off', // TODO translate
|
||||||
|
POLARITY: 'Polarity', // TODO translate
|
||||||
|
ACTIVEHIGH: 'Active High', // TODO translate
|
||||||
|
ACTIVELOW: 'Active Low', // TODO translate
|
||||||
|
UNCHANGED: 'Unchanged', // TODO translate
|
||||||
|
ALWAYS: 'Always', // TODO translate
|
||||||
|
ACTIVITY: 'Activity', // TODO translate
|
||||||
|
CONFIGURE: 'Configure {0}' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const pl: BaseTranslation = {
|
|||||||
USERNAME: '{{Użytkownik|Nazwa użytkownika|}}',
|
USERNAME: '{{Użytkownik|Nazwa użytkownika|}}',
|
||||||
PASSWORD: 'Hasło',
|
PASSWORD: 'Hasło',
|
||||||
SU_PASSWORD: 'Hasło "su"',
|
SU_PASSWORD: 'Hasło "su"',
|
||||||
DASHBOARD: 'Pulpit',
|
|
||||||
SETTINGS_OF: 'Ustawienia {0}',
|
SETTINGS_OF: 'Ustawienia {0}',
|
||||||
HELP_OF: 'Pomoc {0}',
|
HELP_OF: 'Pomoc {0}',
|
||||||
LOGGED_IN: 'Zalogowano użytkownika {name}.',
|
LOGGED_IN: 'Zalogowano użytkownika {name}.',
|
||||||
@@ -37,8 +36,6 @@ const pl: BaseTranslation = {
|
|||||||
VERSION: 'Wersja',
|
VERSION: 'Wersja',
|
||||||
ENTITY_NAME: '{{N|n|}}azwa encji',
|
ENTITY_NAME: '{{N|n|}}azwa encji',
|
||||||
VALUE: '{{W|w|}}artość',
|
VALUE: '{{W|w|}}artość',
|
||||||
DEVICE_DATA: 'Dane z urządzeń',
|
|
||||||
SENSOR_DATA: 'Dane z czujników',
|
|
||||||
DEVICES: 'Urządzenia',
|
DEVICES: 'Urządzenia',
|
||||||
SENSORS: 'Czujniki',
|
SENSORS: 'Czujniki',
|
||||||
RUN_COMMAND: 'Wykonaj komendę',
|
RUN_COMMAND: 'Wykonaj komendę',
|
||||||
@@ -53,7 +50,7 @@ const pl: BaseTranslation = {
|
|||||||
PROBLEM_LOADING: 'Problem z załadowaniem!',
|
PROBLEM_LOADING: 'Problem z załadowaniem!',
|
||||||
ANALOG_SENSOR: '{{u|u||ustawienia u|ustawień u}}rządzeni{{a podłączonego do EMS-ESP|e||a podłączonego do EMS-ESP|a podłączonego do EMS-ESP}}',
|
ANALOG_SENSOR: '{{u|u||ustawienia u|ustawień u}}rządzeni{{a podłączonego do EMS-ESP|e||a podłączonego do EMS-ESP|a podłączonego do EMS-ESP}}',
|
||||||
ANALOG_SENSORS: 'Urządzenia podłączone do EMS-ESP',
|
ANALOG_SENSORS: 'Urządzenia podłączone do EMS-ESP',
|
||||||
SETTINGS: 'ustawienia',
|
SETTINGS: 'ustawie{{nia|ń|}}',
|
||||||
UPDATED_OF: 'Zaktualizowano {0}.',
|
UPDATED_OF: 'Zaktualizowano {0}.',
|
||||||
UPDATE_OF: 'Aktualizacja {0}',
|
UPDATE_OF: 'Aktualizacja {0}',
|
||||||
REMOVED_OF: 'Usunięto ustawienia {0}.',
|
REMOVED_OF: 'Usunięto ustawienia {0}.',
|
||||||
@@ -83,7 +80,6 @@ const pl: BaseTranslation = {
|
|||||||
FAIL: 'Nieudane',
|
FAIL: 'Nieudane',
|
||||||
QUALITY: 'Jakość',
|
QUALITY: 'Jakość',
|
||||||
SCAN_DEVICES: 'Wyszukiwanie nowych urządzeń',
|
SCAN_DEVICES: 'Wyszukiwanie nowych urządzeń',
|
||||||
EMS_BUS_STATUS_TITLE: 'Aktywność',
|
|
||||||
SCAN: 'Skanuj',
|
SCAN: 'Skanuj',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS, telegramy odebrane (Rx)',
|
'EMS, telegramy odebrane (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const pl: BaseTranslation = {
|
|||||||
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
|
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
|
||||||
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
|
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
|
||||||
UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
|
UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
|
||||||
|
HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem',
|
||||||
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica',
|
ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica',
|
||||||
TRIGGER_TIME: 'Wyzwalaj po czasie',
|
TRIGGER_TIME: 'Wyzwalaj po czasie',
|
||||||
@@ -145,13 +142,13 @@ const pl: BaseTranslation = {
|
|||||||
MINUTES: 'minut',
|
MINUTES: 'minut',
|
||||||
HOURS: 'godzin',
|
HOURS: 'godzin',
|
||||||
RESTART: 'Restart',
|
RESTART: 'Restart',
|
||||||
RESTART_TEXT: 'Aby zastosować wprowadzone zmiany interfejs EMS-ESP musi zostać zrestartowany.',
|
RESTART_TEXT: 'Aby zastosować wprowadzone zmiany, interfejs EMS-ESP {{musi zostać|zostanie|}} uruchomiony ponowni{{e.|e|}}',
|
||||||
RESTART_CONFIRM: 'Na pewno chcesz zrestartować interfejs EMS-ESP?',
|
RESTART_CONFIRM: 'Na pewno chcesz zrestartować interfejs EMS-ESP?',
|
||||||
COMMAND: '{{Komenda|KOMENDA|}}',
|
COMMAND: '{{Komenda|KOMENDA|}}',
|
||||||
CUSTOMIZATIONS_RESTART: 'Wszystkie personalizacje zostały usunięte. Restartuję...',
|
CUSTOMIZATIONS_RESTART: 'Wszystkie personalizacje zostały usunięte. Restartuję...',
|
||||||
CUSTOMIZATIONS_FULL: 'Wybrano za dużo obiektów. Wprowadź zmiany w mniejszych partiach.',
|
CUSTOMIZATIONS_FULL: 'Wybrano za dużo obiektów. Wprowadź zmiany w mniejszych partiach.',
|
||||||
CUSTOMIZATIONS_SAVED: 'Personalizacje zostały zapisane.',
|
CUSTOMIZATIONS_SAVED: 'Personalizacje zostały zapisane.',
|
||||||
CUSTOMIZATIONS_HELP_1: 'Wybierz urządzenie EMS, dostosuj opcje lub kliknij by zmienić nazwę encji.',
|
CUSTOMIZATIONS_HELP_1: 'Wybierz urządzenie EMS, a następnie dostosuj opcje lub kliknij na nazwie encji by tę nazwę zmienić',
|
||||||
CUSTOMIZATIONS_HELP_2: 'oznacz jako ulubioną',
|
CUSTOMIZATIONS_HELP_2: 'oznacz jako ulubioną',
|
||||||
CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu',
|
CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu',
|
||||||
CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API',
|
CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API',
|
||||||
@@ -162,15 +159,12 @@ const pl: BaseTranslation = {
|
|||||||
OPTIONS: 'Opcje',
|
OPTIONS: 'Opcje',
|
||||||
NAME: '{{Nazwa|nazwa|}}',
|
NAME: '{{Nazwa|nazwa|}}',
|
||||||
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
||||||
DEVICE_ENTITIES: 'Encje urządzenia',
|
SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
|
||||||
SUPPORT_INFORMATION: 'Informacje dotyczące wsparcia',
|
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP, skorzystaj z wiki w internecie',
|
||||||
CLICK_HERE: 'Kliknij tu',
|
|
||||||
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP skorzystaj z wiki w internecie',
|
|
||||||
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
||||||
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić problem',
|
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić problem',
|
||||||
HELP_INFORMATION_4: 'Zgłaszając problem, nie zapomnij dołączyć informacji o swoim systemie!',
|
HELP_INFORMATION_4: 'Zgłaszając problem, nie zapomnij pobrać i dołączyć informacji o swoim systemie!',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP jest darmowym projektem typu open-source. Aby go wesprzeć, rozważ przyznanie nam gwiazdki na Github!',
|
HELP_INFORMATION_5: 'EMS-ESP jest darmowym projektem typu open-source. Aby go wesprzeć, rozważ przyznanie nam gwiazdki na Github!',
|
||||||
SUPPORT_INFO: 'Pobierz informacje',
|
|
||||||
UPLOAD: 'Wysyłanie',
|
UPLOAD: 'Wysyłanie',
|
||||||
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
||||||
ABORTED: 'zostało przerwane!',
|
ABORTED: 'zostało przerwane!',
|
||||||
@@ -181,34 +175,30 @@ const pl: BaseTranslation = {
|
|||||||
STATUS_OF: 'Status {0}',
|
STATUS_OF: 'Status {0}',
|
||||||
UPLOAD_DOWNLOAD: 'Przesyłanie plików',
|
UPLOAD_DOWNLOAD: 'Przesyłanie plików',
|
||||||
VERSION_ON: 'Aktualnie używasz',
|
VERSION_ON: 'Aktualnie używasz',
|
||||||
SYSTEM_APPLY_FIRMWARE: '',
|
|
||||||
CLOSE: 'Zamknij',
|
CLOSE: 'Zamknij',
|
||||||
USE: 'Aby zaktualizować firmware skorzystaj z funkcji',
|
USE: 'Aby zaktualizować firmware skorzystaj z funkcji',
|
||||||
FACTORY_RESET: 'Ustawienia fabryczne',
|
FACTORY_RESET: 'Ustawienia fabryczne',
|
||||||
SYSTEM_FACTORY_TEXT: 'Interfejs EMS-ESP został przywrócony do ustawień fabrycznych i zostanie teraz ponownie uruchomiony.',
|
SYSTEM_FACTORY_TEXT: 'Interfejs EMS-ESP został przywrócony do ustawień fabrycznych i zostanie teraz ponownie uruchomiony.',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP? ',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP? ',
|
||||||
VERSION_CHECK: 'Sprawd{{ź|zanie|}} wersj{{ę|i|}}',
|
|
||||||
THE_LATEST: 'Najnowsze',
|
THE_LATEST: 'Najnowsze',
|
||||||
OFFICIAL: 'oficjalne',
|
OFFICIAL: 'oficjalne',
|
||||||
DEVELOPMENT: 'testowe',
|
DEVELOPMENT: 'testowe',
|
||||||
RELEASE_IS: 'wydanie to',
|
RELEASE_IS: 'wydanie to',
|
||||||
RELEASE_NOTES: 'lista zmian',
|
RELEASE_NOTES: 'lista zmian',
|
||||||
EMS_ESP_VER: 'Wersja EMS-ESP',
|
EMS_ESP_VER: 'Wersja EMS-ESP',
|
||||||
PLATFORM: 'Urządzenie (platforma / SDK)',
|
|
||||||
UPTIME: 'Czas działania systemu',
|
UPTIME: 'Czas działania systemu',
|
||||||
CPU_FREQ: 'Taktowanie CPU',
|
|
||||||
HEAP: 'HEAP (wolne / maksymalny przydział)',
|
HEAP: 'HEAP (wolne / maksymalny przydział)',
|
||||||
PSRAM: 'PSRAM (rozmiar / wolne)',
|
PSRAM: 'PSRAM (rozmiar / wolne)',
|
||||||
FLASH: 'FLASH (rozmiar / taktowanie)',
|
FLASH: 'FLASH (rozmiar / taktowanie)',
|
||||||
APPSIZE: 'Aplikacja (wykorzystane / wolne)',
|
APPSIZE: 'Aplikacja (partycja: wykorzystane / wolne)',
|
||||||
FILESYSTEM: 'System plików (wykorzystane / wolne)',
|
FILESYSTEM: 'System plików (wykorzystane / wolne)',
|
||||||
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
||||||
COMPACT: 'Kompaktowy',
|
COMPACT: 'Kompaktowy',
|
||||||
ENABLE_OTA: 'Aktywuj aktualizację OTA',
|
ENABLE_OTA: 'Aktywuj aktualizację OTA',
|
||||||
DOWNLOAD_CUSTOMIZATION_TEXT: 'Pobierz personalizacje.',
|
DOWNLOAD_CUSTOMIZATION_TEXT: 'Pobierz personalizacje.',
|
||||||
DOWNLOAD_SCHEDULE_TEXT: 'Pobierz harmonogram zdarzeń.',
|
DOWNLOAD_SCHEDULE_TEXT: 'Pobierz harmonogram zdarzeń.',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uważaj jeśli udostępniasz plik z ustawieniami, ponieważ zawiera on hasła oraz inne wrażliwe informacje!',
|
DOWNLOAD_SETTINGS_TEXT: 'Pobierz ustawienia aplikacji. Uwaga! Plik z ustawieniami zawiera hasła oraz inne wrażliwe informacje systemowe! Nie udostepniaj go pochopnie!',
|
||||||
UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji (.md5).',
|
UPLOAD_TEXT: 'Wyślij firmware (.bin), ustawienia lub personalizacje (.json). Opcjonalnie, wyślij wcześniej plik walidacji z sumą kontrolną (.md5).',
|
||||||
UPLOADING: 'Wysłano',
|
UPLOADING: 'Wysłano',
|
||||||
UPLOAD_DROP_TEXT: 'Przeciągnij tutaj plik lub kliknij',
|
UPLOAD_DROP_TEXT: 'Przeciągnij tutaj plik lub kliknij',
|
||||||
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
||||||
@@ -246,6 +236,7 @@ const pl: BaseTranslation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||||
MQTT_INT_SOLAR: 'Panele solarne',
|
MQTT_INT_SOLAR: 'Panele solarne',
|
||||||
MQTT_INT_MIXER: 'Mieszacze',
|
MQTT_INT_MIXER: 'Mieszacze',
|
||||||
|
MQTT_INT_WATER: 'Woda',
|
||||||
MQTT_QUEUE: 'Kolejka MQTT',
|
MQTT_QUEUE: 'Kolejka MQTT',
|
||||||
DEFAULT: '{{Pozostałe|Domyślna|}}',
|
DEFAULT: '{{Pozostałe|Domyślna|}}',
|
||||||
MQTT_ENTITY_FORMAT: 'Format "Entity ID"',
|
MQTT_ENTITY_FORMAT: 'Format "Entity ID"',
|
||||||
@@ -281,14 +272,15 @@ const pl: BaseTranslation = {
|
|||||||
SCAN_AGAIN: 'Skanuj ponownie',
|
SCAN_AGAIN: 'Skanuj ponownie',
|
||||||
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
||||||
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
||||||
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi', // and enable ETH // TODO translate
|
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi i włączyć ETH',
|
||||||
|
NETWORK_BLANK_BSSID: 'pozostaw puste aby używać tylko SSID',
|
||||||
TX_POWER: 'Moc nadawania',
|
TX_POWER: 'Moc nadawania',
|
||||||
HOSTNAME: 'Nazwa w sieci',
|
HOSTNAME: 'Nazwa w sieci',
|
||||||
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
||||||
NETWORK_LOW_BAND: 'Używaj mniejszej szerokości pasma WiFi (20MHz)',
|
NETWORK_LOW_BAND: 'Używaj mniejszej szerokości pasma WiFi (20MHz)',
|
||||||
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS',
|
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS',
|
||||||
NETWORK_ENABLE_CORS: 'Włącz wsparcie dla CORS',
|
NETWORK_ENABLE_CORS: 'Włącz wsparcie dla CORS',
|
||||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
NETWORK_CORS_ORIGIN: 'CORS Origin',
|
||||||
NETWORK_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
|
NETWORK_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
|
||||||
NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
|
NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
|
||||||
NETWORK_GATEWAY: 'Brama',
|
NETWORK_GATEWAY: 'Brama',
|
||||||
@@ -319,10 +311,20 @@ const pl: BaseTranslation = {
|
|||||||
CUSTOM_ENTITIES: '{{N|n|}}iestandardowe{{|j|}} encj{{e|i|}}',
|
CUSTOM_ENTITIES: '{{N|n|}}iestandardowe{{|j|}} encj{{e|i|}}',
|
||||||
ENTITIES_HELP_1: 'Zdefiniuj niestandardowe encje dla magistrali EMS.',
|
ENTITIES_HELP_1: 'Zdefiniuj niestandardowe encje dla magistrali EMS.',
|
||||||
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
||||||
WRITEABLE: 'zapisywalna',
|
WRITEABLE: 'Zapisywalna',
|
||||||
SHOWING: 'Wyświetlane',
|
SHOWING: 'Wyświetlane',
|
||||||
SEARCH: 'Szukaj',
|
SEARCH: 'Szukaj',
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
CERT: 'Certyfikat główny TLS (pozostaw puste dla TLS-insecure)',
|
||||||
|
ENABLE_TLS: 'Włącz wsparcie dla TLS',
|
||||||
|
ON: 'włączony',
|
||||||
|
OFF: 'wyłączony',
|
||||||
|
POLARITY: 'Typ przekaźnika',
|
||||||
|
ACTIVEHIGH: 'Wyzwalany stanem wysokim',
|
||||||
|
ACTIVELOW: 'Wyzwalany stanem niskim',
|
||||||
|
UNCHANGED: 'Zachowaj stan',
|
||||||
|
ALWAYS: 'Zawsze',
|
||||||
|
ACTIVITY: 'Aktywność',
|
||||||
|
CONFIGURE: 'Konfiguracja {0}'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
331
interface/src/i18n/sk/index.ts
Normal file
331
interface/src/i18n/sk/index.ts
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
import type { Translation } from '../i18n-types';
|
||||||
|
/* prettier-ignore */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
const sk: Translation = {
|
||||||
|
LANGUAGE: 'Jazyk',
|
||||||
|
RETRY: 'Opakovať',
|
||||||
|
LOADING: 'Načítanie',
|
||||||
|
IS_REQUIRED: '{0} je požadovaných',
|
||||||
|
SIGN_IN: 'Prihlásiť sa',
|
||||||
|
SIGN_OUT: 'Odhlásiť sa',
|
||||||
|
USERNAME: 'Užívateľské meno',
|
||||||
|
PASSWORD: 'Heslo',
|
||||||
|
SU_PASSWORD: 'su heslo',
|
||||||
|
SETTINGS_OF: '{0} Nastavenia',
|
||||||
|
HELP_OF: '{0} Pomoc',
|
||||||
|
LOGGED_IN: 'Prihlásený ako {name}',
|
||||||
|
PLEASE_SIGNIN: 'Ak chcete pokračovať, prihláste sa',
|
||||||
|
UPLOAD_SUCCESSFUL: 'Nahratie úspešné',
|
||||||
|
DOWNLOAD_SUCCESSFUL: 'Stiahnutie úspešné',
|
||||||
|
INVALID_LOGIN: 'Nesprávne prihlasovacie údaje',
|
||||||
|
NETWORK: 'Sieť',
|
||||||
|
SECURITY: 'Zabezpečenie',
|
||||||
|
ONOFF_CAP: 'ZAP/VYP',
|
||||||
|
ONOFF: 'zap/vyp',
|
||||||
|
TYPE: 'Typ',
|
||||||
|
DESCRIPTION: 'Popis',
|
||||||
|
ENTITIES: 'Entity',
|
||||||
|
REFRESH: 'Obnoviť',
|
||||||
|
EXPORT: 'Export',
|
||||||
|
DEVICE_DETAILS: 'Detaily zariadenia',
|
||||||
|
ID_OF: '{0} ID',
|
||||||
|
DEVICE: 'Zariadenie',
|
||||||
|
PRODUCT: 'Produkt',
|
||||||
|
VERSION: 'Verzia',
|
||||||
|
BRAND: 'Značka',
|
||||||
|
ENTITY_NAME: 'Názov entity',
|
||||||
|
VALUE: '{{Hodnota|hodnota}}',
|
||||||
|
DEVICES: 'Zariadenia',
|
||||||
|
SENSORS: 'Snímače',
|
||||||
|
RUN_COMMAND: 'Volať príkaz',
|
||||||
|
CHANGE_VALUE: 'Zmena hodnoty',
|
||||||
|
CANCEL: 'Zrušiť',
|
||||||
|
RESET: 'Reset',
|
||||||
|
APPLY_CHANGES: 'Aplikovať zmeny ({0})',
|
||||||
|
UPDATE: 'Aktualizovať',
|
||||||
|
EXECUTE: 'Spustiť',
|
||||||
|
REMOVE: 'Odstrániť',
|
||||||
|
PROBLEM_UPDATING: 'Problém s aktualizáciou',
|
||||||
|
PROBLEM_LOADING: 'Problém s načítaním',
|
||||||
|
ANALOG_SENSOR: 'Analógový snímač',
|
||||||
|
ANALOG_SENSORS: 'Analógové snímače',
|
||||||
|
SETTINGS: 'Nastavenia',
|
||||||
|
UPDATED_OF: '{0} aktualizovaných',
|
||||||
|
UPDATE_OF: '{0} aktualizované',
|
||||||
|
REMOVED_OF: '{0} odstránených',
|
||||||
|
DELETION_OF: '{0} zmazaných',
|
||||||
|
OFFSET: 'Ofset',
|
||||||
|
FACTOR: 'Faktor',
|
||||||
|
FREQ: 'Frekvencia',
|
||||||
|
DUTY_CYCLE: 'Duty Cycle',
|
||||||
|
UNIT: 'UoM',
|
||||||
|
STARTVALUE: 'Počiatočná hodnota',
|
||||||
|
WARN_GPIO: 'Upozornenie: Buďte opatrní pri priraďovaní GPIO!',
|
||||||
|
EDIT: 'Editovať',
|
||||||
|
SENSOR: 'Snímač',
|
||||||
|
TEMP_SENSOR: 'Snímač teploty',
|
||||||
|
TEMP_SENSORS: 'Snímače teploty',
|
||||||
|
WRITE_CMD_SENT: 'Príkaz zápisu bol odoslaný',
|
||||||
|
EMS_BUS_WARNING: 'Zbernica EMS odpojená. Ak toto upozornenie pretrváva aj po niekoľkých sekundách, skontrolujte nastavenia a profil dosky',
|
||||||
|
EMS_BUS_SCANNING: 'Zisťovanie EMS zariadení...',
|
||||||
|
CONNECTED: 'Pripojené',
|
||||||
|
TX_ISSUES: 'Problémy s Tx – skontrolujte Tx režim',
|
||||||
|
DISCONNECTED: 'Odpojené',
|
||||||
|
EMS_SCAN: 'Naozaj chcete spustiť úplnú kontrolu zariadenia zbernice EMS?',
|
||||||
|
EMS_BUS_STATUS: 'Stav zbernice EMS',
|
||||||
|
ACTIVE_DEVICES: 'Aktívne zariadenia a snímače',
|
||||||
|
EMS_DEVICE: 'EMS zariadenie',
|
||||||
|
SUCCESS: 'ÚSPEŠNÉ',
|
||||||
|
FAIL: 'ZLÝHANIE',
|
||||||
|
QUALITY: 'KVALITA',
|
||||||
|
SCAN_DEVICES: 'Scan pre nové zariadenia',
|
||||||
|
SCAN: 'Scan',
|
||||||
|
STATUS_NAMES: [
|
||||||
|
'EMS Telegramy prijaté (Rx)',
|
||||||
|
'EMS Čítania (Tx)',
|
||||||
|
'EMS Zápisy (Tx)',
|
||||||
|
'Čítanie snímačov teploty',
|
||||||
|
'Čítanie analógových snímačov',
|
||||||
|
'MQTT Publikovanie',
|
||||||
|
'Externé API volania',
|
||||||
|
'Syslog správy'
|
||||||
|
],
|
||||||
|
NUM_DEVICES: '{num} Zariaden{{í|ie|ia|ia|í|í}}',
|
||||||
|
NUM_TEMP_SENSORS: '{num} Teplotn{{ých|ý|é|é|ých|ých}} sníma{{čov|č|če|če|čov|čov}}',
|
||||||
|
NUM_ANALOG_SENSORS: '{num} Analogov{{ých|ý|é|é|ých|ých}} sníma{{čov|č|če|če|čov|čov}}',
|
||||||
|
NUM_DAYS: '{num} d{{ní|eň|ní|ní|ní|ní}}',
|
||||||
|
NUM_SECONDS: '{num} sek{{únd|unda|undy|undy|únd|únd}}',
|
||||||
|
NUM_HOURS: '{num} hod{{ín|ina|iny|iny|ín|ín}}',
|
||||||
|
NUM_MINUTES: '{num} minú{{t|ta|ty|ty|t|t}}',
|
||||||
|
APPLICATION_SETTINGS: 'Nastavenia aplikácie',
|
||||||
|
CUSTOMIZATIONS: 'Prispôsobenia',
|
||||||
|
APPLICATION_RESTARTING: 'EMS-ESP sa reštartuje',
|
||||||
|
INTERFACE_BOARD_PROFILE: 'Profil dosky rozhrania',
|
||||||
|
BOARD_PROFILE_TEXT: 'Vyberte vopred nakonfigurovaný profil dosky rozhrania zo zoznamu nižšie, alebo vyberte možnosť Vlastné a nakonfigurujte svoje vlastné hardvérové nastavenia',
|
||||||
|
BOARD_PROFILE: 'Profil dosky',
|
||||||
|
CUSTOM: 'Vlastné',
|
||||||
|
GPIO_OF: '{0} GPIO',
|
||||||
|
BUTTON: 'Tlačidlo',
|
||||||
|
TEMPERATURE: 'Teplota',
|
||||||
|
PHY_TYPE: 'Eth PHY Typ',
|
||||||
|
DISABLED: 'zakázané',
|
||||||
|
TX_MODE: 'Tx režim',
|
||||||
|
HARDWARE: 'Hardware',
|
||||||
|
EMS_BUS: '{{BUS|EMS BUS}}',
|
||||||
|
GENERAL_OPTIONS: 'Všeobecné možnosti',
|
||||||
|
LANGUAGE_ENTITIES: 'Jazyk (pre entity zariadenia)',
|
||||||
|
HIDE_LED: 'Skryť LED',
|
||||||
|
ENABLE_TELNET: 'Povoliť Telnet konzolu',
|
||||||
|
ENABLE_ANALOG: 'Povoliť analógové snímače',
|
||||||
|
CONVERT_FAHRENHEIT: 'Previesť hodnoty teploty na °F',
|
||||||
|
BYPASS_TOKEN: 'Vynechajte autorizáciu prístupového tokenu pri volaniach API',
|
||||||
|
READONLY: 'Povoliť režim len na čítanie (blokuje všetky odchádzajúce príkazy EMS Tx Write)',
|
||||||
|
UNDERCLOCK_CPU: 'Podtaktovanie rýchlosti procesora',
|
||||||
|
HEATINGOFF: 'Spustiť kotol s vynúteným vykurovaním',
|
||||||
|
|
||||||
|
ENABLE_SHOWER_TIMER: 'Povoliť časovač sprchovania',
|
||||||
|
ENABLE_SHOWER_ALERT: 'Povoliť upozornenie na sprchu',
|
||||||
|
TRIGGER_TIME: 'Čas spustenia',
|
||||||
|
COLD_SHOT_DURATION: 'Trvanie studeného záberu',
|
||||||
|
FORMATTING_OPTIONS: 'Možnosti formátovania',
|
||||||
|
BOOLEAN_FORMAT_DASHBOARD: 'Panel Boolean formát',
|
||||||
|
BOOLEAN_FORMAT_API: 'Boolean formát API/MQTT',
|
||||||
|
ENUM_FORMAT: 'Enum formát API/MQTT',
|
||||||
|
INDEX: 'Index',
|
||||||
|
ENABLE_PARASITE: 'Povoliť parazité napájanie DS18B20',
|
||||||
|
LOGGING: 'Logovanie',
|
||||||
|
LOG_HEX: 'Záznam telegramov EMS v hexadecimálnej sústave',
|
||||||
|
ENABLE_SYSLOG: 'Povoliť Syslog',
|
||||||
|
LOG_LEVEL: 'Log úroveň',
|
||||||
|
MARK_INTERVAL: 'Označenie intervalu',
|
||||||
|
SECONDS: 'sekundy',
|
||||||
|
MINUTES: 'minúty',
|
||||||
|
HOURS: 'hodiny',
|
||||||
|
RESTART: 'Reštart',
|
||||||
|
RESTART_TEXT: 'EMS-ESP sa musí reštartovať, aby sa použili zmenené systémové nastavenia',
|
||||||
|
RESTART_CONFIRM: 'Ste si istí, že chcete reštartovať EMS-ESP?',
|
||||||
|
COMMAND: 'Príkaz',
|
||||||
|
CUSTOMIZATIONS_RESTART: 'Ste si istí, že chcete reštartovať EMS-ESP?',
|
||||||
|
CUSTOMIZATIONS_FULL: 'Vybrané subjekty prekročili limit. Prosím, ukladajte v dávkach',
|
||||||
|
CUSTOMIZATIONS_SAVED: 'Uložené prispôsobenia',
|
||||||
|
CUSTOMIZATIONS_HELP_1: 'Vyberte zariadenie a prispôsobte možnosti entít alebo kliknutím premenujte',
|
||||||
|
CUSTOMIZATIONS_HELP_2: 'označiť ako obľúbené',
|
||||||
|
CUSTOMIZATIONS_HELP_3: 'zakázať akciu zápisu',
|
||||||
|
CUSTOMIZATIONS_HELP_4: 'vylúčiť z MQTT a API',
|
||||||
|
CUSTOMIZATIONS_HELP_5: 'skryť z panela',
|
||||||
|
CUSTOMIZATIONS_HELP_6: 'odstrániť z pamäte',
|
||||||
|
SELECT_DEVICE: 'Zvoliť zariadenie',
|
||||||
|
SET_ALL: 'nastaviť všetko',
|
||||||
|
OPTIONS: 'Možnosti',
|
||||||
|
NAME: 'Názov',
|
||||||
|
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
||||||
|
SUPPORT_INFORMATION: 'Informácie pre podporu',
|
||||||
|
HELP_INFORMATION_1: 'Navštívte online wiki, kde nájdete pokyny na konfiguráciu EMS-ESP',
|
||||||
|
HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server',
|
||||||
|
HELP_INFORMATION_3: 'Ak chcete požiadať o funkciu alebo nahlásiť chybu',
|
||||||
|
HELP_INFORMATION_4: 'nezabudnite si stiahnuť a pripojiť informácie o vašom systéme, aby ste mohli rýchlejšie reagovať pri nahlasovaní problému',
|
||||||
|
HELP_INFORMATION_5: 'EMS-ESP je bezplatný a open source projekt. Podporte jeho budúci vývoj tým, že mu dáte hviezdičku na Github!',
|
||||||
|
UPLOAD: 'Nahrať',
|
||||||
|
DOWNLOAD: '{{S|s|s}}tiahnuť',
|
||||||
|
ABORTED: 'zrušené',
|
||||||
|
FAILED: 'chybné',
|
||||||
|
SUCCESSFUL: 'úspešné',
|
||||||
|
SYSTEM: 'Systém',
|
||||||
|
LOG_OF: '{0} Log',
|
||||||
|
STATUS_OF: '{0} Stav',
|
||||||
|
UPLOAD_DOWNLOAD: 'Nahrať/Stiahnuť',
|
||||||
|
VERSION_ON: 'Momentálne nainštalovaná verzia: ',
|
||||||
|
CLOSE: 'Zatvoriť',
|
||||||
|
USE: 'Použiť',
|
||||||
|
FACTORY_RESET: 'Továrenské nastavenia',
|
||||||
|
SYSTEM_FACTORY_TEXT: 'Zariadenie bolo obnovené z výroby a teraz sa reštartuje',
|
||||||
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Naozaj chcete resetovať EMS-ESP na predvolené výrobné nastavenia?',
|
||||||
|
THE_LATEST: 'Posledná',
|
||||||
|
OFFICIAL: 'officiálna',
|
||||||
|
DEVELOPMENT: 'vývojárska',
|
||||||
|
RELEASE_IS: 'verzia je',
|
||||||
|
RELEASE_NOTES: 'poznámky k verzii',
|
||||||
|
EMS_ESP_VER: 'EMS-ESP verzia',
|
||||||
|
UPTIME: 'Beh systému',
|
||||||
|
HEAP: 'Zásobník (voľné / max pridelenie)',
|
||||||
|
PSRAM: 'PSRAM (Veľkosť / Voľné)',
|
||||||
|
FLASH: 'Flash chip (Veľkosť / Rýchlosť)',
|
||||||
|
APPSIZE: 'Applikácia (Oddiel: Použité / Voľné)',
|
||||||
|
FILESYSTEM: 'Súborový systém (Použité / Voľné)',
|
||||||
|
BUFFER_SIZE: 'Buffer-max.veľkosť',
|
||||||
|
COMPACT: 'Kompaktné',
|
||||||
|
ENABLE_OTA: 'Povoliť OTA aktualizácie',
|
||||||
|
DOWNLOAD_CUSTOMIZATION_TEXT: 'Stiahnutie prispôsobení entity',
|
||||||
|
DOWNLOAD_SCHEDULE_TEXT: 'Stiahnutie plánovača udalostí',
|
||||||
|
DOWNLOAD_SETTINGS_TEXT: 'Stiahnite si nastavenia aplikácie. Pri zdieľaní nastavení buďte opatrní, pretože tento súbor obsahuje heslá a iné citlivé systémové informácie.',
|
||||||
|
UPLOAD_TEXT: 'Najskôr nahrajte nový súbor firmvéru (.bin), nastavenia alebo prispôsobenia (.json), pre voliteľné overenie nahrajte súbor (.md5)',
|
||||||
|
UPLOADING: 'Nahrávanie',
|
||||||
|
UPLOAD_DROP_TEXT: 'Potiahnúť a pripnúť súbor alebo kliknúť sem',
|
||||||
|
ERROR: 'Neočakávaná chyba, prosím skúste to znova',
|
||||||
|
TIME_SET: 'Nastavený čas',
|
||||||
|
MANAGE_USERS: 'Správa používateľov',
|
||||||
|
IS_ADMIN: 'je Admin',
|
||||||
|
USER_WARNING: 'Musíte mať nakonfigurovaného aspoň jedného používateľa administrátora',
|
||||||
|
ADD: 'Pridať',
|
||||||
|
ACCESS_TOKEN_FOR: 'Prístupový token pre',
|
||||||
|
ACCESS_TOKEN_TEXT: 'Nižšie uvedený token sa používa pri volaniach REST API, ktoré vyžadujú autorizáciu. Môže byť odovzdaný buď ako token Bearer v hlavičke Authorization (Autorizácia), alebo v parametri dotazu URL access_token.',
|
||||||
|
GENERATING_TOKEN: 'Generovanie tokenu',
|
||||||
|
USER: 'Užívateľ',
|
||||||
|
MODIFY: 'Upraviť',
|
||||||
|
SU_TEXT: 'Heslo su (superužívateľ) sa používa na podpisovanie autentifikačných tokenov a tiež na povolenie oprávnení správcu v rámci konzoly.',
|
||||||
|
NOT_ENABLED: 'Nie je povolené',
|
||||||
|
ERRORS_OF: '{0} errory',
|
||||||
|
DISCONNECT_REASON: 'Dôvod odpojenia',
|
||||||
|
ENABLE_MQTT: 'Povoliť MQTT',
|
||||||
|
BROKER: 'Broker',
|
||||||
|
CLIENT: 'Klient',
|
||||||
|
BASE_TOPIC: 'Base',
|
||||||
|
OPTIONAL: 'voliteľné',
|
||||||
|
FORMATTING: 'Formátovanie',
|
||||||
|
MQTT_FORMAT: 'Formát témy/záťaže',
|
||||||
|
MQTT_NEST_1: 'Vnorené do jednej témy',
|
||||||
|
MQTT_NEST_2: 'Ako jednotlivé témy',
|
||||||
|
MQTT_RESPONSE: 'Publikovanie výstupu príkazu do témy `response`',
|
||||||
|
MQTT_PUBLISH_TEXT_1: 'Zverejňovanie tém jednotlivých hodnôt pri zmene',
|
||||||
|
MQTT_PUBLISH_TEXT_2: 'Publikovanie do tém príkazov (ioBroker)',
|
||||||
|
MQTT_PUBLISH_TEXT_3: 'Povolenie zisťovania MQTT',
|
||||||
|
MQTT_PUBLISH_TEXT_4: 'Predpona tém Discovery',
|
||||||
|
MQTT_PUBLISH_TEXT_5: 'Typ zistenia',
|
||||||
|
MQTT_PUBLISH_INTERVALS: 'Intervaly zverejňovania',
|
||||||
|
MQTT_INT_BOILER: 'Kotly a tepelné čerpadlá',
|
||||||
|
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||||
|
MQTT_INT_SOLAR: 'Solárne moduly',
|
||||||
|
MQTT_INT_MIXER: 'Zmiešavacie moduley',
|
||||||
|
MQTT_INT_WATER: 'Voda moduley',
|
||||||
|
MQTT_QUEUE: 'Fronta MQTT',
|
||||||
|
DEFAULT: 'Predvolené',
|
||||||
|
MQTT_ENTITY_FORMAT: 'ID formát entity',
|
||||||
|
MQTT_ENTITY_FORMAT_0: 'Jedna inštancia, dlhý názov (v3.4)',
|
||||||
|
MQTT_ENTITY_FORMAT_1: 'Jedna inštancia, krátky názov',
|
||||||
|
MQTT_ENTITY_FORMAT_2: 'Viacero inštancií, krátky názov',
|
||||||
|
MQTT_CLEAN_SESSION: 'Nastavenie čistej relácie',
|
||||||
|
MQTT_RETAIN_FLAG: 'Vždy nastaviť príznak Retain',
|
||||||
|
INACTIVE: 'Neaktívne',
|
||||||
|
ACTIVE: 'Aktívne',
|
||||||
|
UNKNOWN: 'Neznáme',
|
||||||
|
SET_TIME: 'Nastavený čas',
|
||||||
|
SET_TIME_TEXT: 'Na nastavenie času zadajte miestny dátum a čas nižšie',
|
||||||
|
LOCAL_TIME: 'Lokálny čas',
|
||||||
|
UTC_TIME: 'UTC čas',
|
||||||
|
ENABLE_NTP: 'Povoliť NTP',
|
||||||
|
NTP_SERVER: 'NTP Server',
|
||||||
|
TIME_ZONE: 'Časová zóna',
|
||||||
|
ACCESS_POINT: 'Prístupový bod',
|
||||||
|
AP_PROVIDE: 'Povoliť prístupový bod',
|
||||||
|
AP_PROVIDE_TEXT_1: 'vždy',
|
||||||
|
AP_PROVIDE_TEXT_2: 'keď je WiFi odpojená',
|
||||||
|
AP_PROVIDE_TEXT_3: 'nikdy',
|
||||||
|
AP_PREFERRED_CHANNEL: 'Preferovaný kanál',
|
||||||
|
AP_HIDE_SSID: 'Skryť SSID',
|
||||||
|
AP_CLIENTS: 'AP klienti',
|
||||||
|
AP_MAX_CLIENTS: 'Max klientov',
|
||||||
|
AP_LOCAL_IP: 'Lokálna IP',
|
||||||
|
NETWORK_SCAN: 'Scan WiFi siete',
|
||||||
|
IDLE: 'Nečinné',
|
||||||
|
LOST: 'Stratené',
|
||||||
|
SCANNING: 'Scanovanie',
|
||||||
|
SCAN_AGAIN: 'Scanovať znova',
|
||||||
|
NETWORK_SCANNER: 'Sieťový scanner',
|
||||||
|
NETWORK_NO_WIFI: 'WiFi siete nenájdené',
|
||||||
|
NETWORK_BLANK_SSID: 'nechajte prázdne, ak chcete zakázať WiFi a povoliť ETH',
|
||||||
|
NETWORK_BLANK_BSSID: 'ponechajte prázdne, ak chcete používať iba SSID',
|
||||||
|
TX_POWER: 'Tx výkon',
|
||||||
|
HOSTNAME: 'Hostname',
|
||||||
|
NETWORK_DISABLE_SLEEP: 'Zakázanie režimu spánku WiFi',
|
||||||
|
NETWORK_LOW_BAND: 'Používanie menšej šírky pásma WiFi',
|
||||||
|
NETWORK_USE_DNS: 'Povoliť mDNS službu',
|
||||||
|
NETWORK_ENABLE_CORS: 'Povoliť CORS',
|
||||||
|
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||||
|
NETWORK_ENABLE_IPV6: 'Povoliť podporu IPv6',
|
||||||
|
NETWORK_FIXED_IP: 'Použiť fixnú IP adresu',
|
||||||
|
NETWORK_GATEWAY: 'Brána',
|
||||||
|
NETWORK_SUBNET: 'Maska podsiete',
|
||||||
|
NETWORK_DNS: 'DNS servery',
|
||||||
|
ADDRESS_OF: '{0} adresa',
|
||||||
|
ADMIN: 'Admin',
|
||||||
|
GUEST: 'Hosť',
|
||||||
|
NEW: 'Nová',
|
||||||
|
NEW_NAME_OF: 'Nový názov {0}',
|
||||||
|
ENTITY: 'entita',
|
||||||
|
MIN: 'min',
|
||||||
|
MAX: 'max',
|
||||||
|
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
|
||||||
|
BLOCK_NAVIGATE_2: 'Ak prejdete na inú stránku, neuložené zmeny sa stratia. Ste si istí, že chcete opustiť túto stránku?',
|
||||||
|
STAY: 'Zostať',
|
||||||
|
LEAVE: 'Opustiť',
|
||||||
|
SCHEDULER: 'Plánovač',
|
||||||
|
SCHEDULER_HELP_1: 'Automatizujte príkazy pridaním naplánovaných udalostí nižšie. Nastavte jedinečné meno na aktiváciu/deaktiváciu cez API/MQTT.',
|
||||||
|
SCHEDULER_HELP_2: 'Použite 00:00 na jednorazové spustenie pri štarte',
|
||||||
|
SCHEDULE: 'Plánovač',
|
||||||
|
TIME: 'Čas',
|
||||||
|
TIMER: 'Časovač',
|
||||||
|
SCHEDULE_UPDATED: 'Plánovanie aktualizované',
|
||||||
|
SCHEDULE_TIMER_1: 'pri spustení',
|
||||||
|
SCHEDULE_TIMER_2: 'každú minútu',
|
||||||
|
SCHEDULE_TIMER_3: 'každú hodinu',
|
||||||
|
CUSTOM_ENTITIES: 'Vlastné entity',
|
||||||
|
ENTITIES_HELP_1: 'Získavanie vlastných entít zo zbernice EMS',
|
||||||
|
ENTITIES_UPDATED: 'Aktualizované entity',
|
||||||
|
WRITEABLE: 'Zapísateľný',
|
||||||
|
SHOWING: 'Zobrazenie',
|
||||||
|
SEARCH: 'Vyhľadať',
|
||||||
|
CERT: 'Koreňový certifikát TLS (ak chcete vypnúť TLS, nechajte prázdne)',
|
||||||
|
ENABLE_TLS: 'Povoliť TLS',
|
||||||
|
ON: 'Zap',
|
||||||
|
OFF: 'Vyp',
|
||||||
|
POLARITY: 'Polarita',
|
||||||
|
ACTIVEHIGH: 'Aktívny Vysoký',
|
||||||
|
ACTIVELOW: 'Aktívny Nízky',
|
||||||
|
UNCHANGED: 'Nezmenené',
|
||||||
|
ALWAYS: 'Vždy',
|
||||||
|
ACTIVITY: 'Aktivita',
|
||||||
|
CONFIGURE: 'Konfiguracia {0}'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default sk;
|
||||||
@@ -12,7 +12,6 @@ const sv: Translation = {
|
|||||||
USERNAME: 'Användarnamn',
|
USERNAME: 'Användarnamn',
|
||||||
PASSWORD: 'Lösenord',
|
PASSWORD: 'Lösenord',
|
||||||
SU_PASSWORD: 'su Lösenord',
|
SU_PASSWORD: 'su Lösenord',
|
||||||
DASHBOARD: 'Kontrollpanel',
|
|
||||||
SETTINGS_OF: '{0} Inställningar',
|
SETTINGS_OF: '{0} Inställningar',
|
||||||
HELP_OF: '{0} Hjälp',
|
HELP_OF: '{0} Hjälp',
|
||||||
LOGGED_IN: 'Inloggad som {name}',
|
LOGGED_IN: 'Inloggad som {name}',
|
||||||
@@ -37,8 +36,6 @@ const sv: Translation = {
|
|||||||
BRAND: 'Fabrikat',
|
BRAND: 'Fabrikat',
|
||||||
ENTITY_NAME: 'Entitetsnamn',
|
ENTITY_NAME: 'Entitetsnamn',
|
||||||
VALUE: '{{Värde|värde}}',
|
VALUE: '{{Värde|värde}}',
|
||||||
DEVICE_DATA: 'Enhets data',
|
|
||||||
SENSOR_DATA: 'Sensor data',
|
|
||||||
DEVICES: 'Enheter',
|
DEVICES: 'Enheter',
|
||||||
SENSORS: 'Sensorer',
|
SENSORS: 'Sensorer',
|
||||||
RUN_COMMAND: 'Kör Kommando',
|
RUN_COMMAND: 'Kör Kommando',
|
||||||
@@ -83,7 +80,6 @@ const sv: Translation = {
|
|||||||
FAIL: 'Misslyckades',
|
FAIL: 'Misslyckades',
|
||||||
QUALITY: 'Kvalitet',
|
QUALITY: 'Kvalitet',
|
||||||
SCAN_DEVICES: 'Sök efter nya enheter',
|
SCAN_DEVICES: 'Sök efter nya enheter',
|
||||||
EMS_BUS_STATUS_TITLE: 'EMS-buss & aktivitetsstatus',
|
|
||||||
SCAN: 'Sök',
|
SCAN: 'Sök',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS-telegram (Rx)',
|
'EMS-telegram (Rx)',
|
||||||
@@ -126,6 +122,7 @@ const sv: Translation = {
|
|||||||
BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop',
|
BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop',
|
||||||
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
|
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
|
||||||
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
|
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
|
||||||
|
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
||||||
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer',
|
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer',
|
||||||
ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning',
|
ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning',
|
||||||
TRIGGER_TIME: 'Aktiveringstid',
|
TRIGGER_TIME: 'Aktiveringstid',
|
||||||
@@ -162,15 +159,12 @@ const sv: Translation = {
|
|||||||
OPTIONS: 'Alternativ',
|
OPTIONS: 'Alternativ',
|
||||||
NAME: 'Namn',
|
NAME: 'Namn',
|
||||||
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar inklusive inställningar för Temperatur och Analoga sensorer?',
|
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar inklusive inställningar för Temperatur och Analoga sensorer?',
|
||||||
DEVICE_ENTITIES: 'Enhets-entiteter',
|
|
||||||
SUPPORT_INFORMATION: 'Supportinformation',
|
SUPPORT_INFORMATION: 'Supportinformation',
|
||||||
CLICK_HERE: 'Klicka Här',
|
|
||||||
HELP_INFORMATION_1: 'Besök Wikin för instruktioner för hur du kan konfigurera EMS-ESP',
|
HELP_INFORMATION_1: 'Besök Wikin för instruktioner för hur du kan konfigurera EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
|
HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
|
||||||
HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg',
|
HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg',
|
||||||
HELP_INFORMATION_4: 'Bifoga din systeminformation för snabbare hantering när du rapporterar ett problem',
|
HELP_INFORMATION_4: 'Bifoga din systeminformation för snabbare hantering när du rapporterar ett problem',
|
||||||
HELP_INFORMATION_5: 'EMS-ESP är gratis och är öppen källkod. Bidra till utvecklingen genom att ge oss en stjärna på GitHub!',
|
HELP_INFORMATION_5: 'EMS-ESP är gratis och är öppen källkod. Bidra till utvecklingen genom att ge oss en stjärna på GitHub!',
|
||||||
SUPPORT_INFO: 'Supportinfo',
|
|
||||||
UPLOAD: 'Uppladdning',
|
UPLOAD: 'Uppladdning',
|
||||||
DOWNLOAD: '{{N|n|n}}edladdning',
|
DOWNLOAD: '{{N|n|n}}edladdning',
|
||||||
ABORTED: 'Avbruten',
|
ABORTED: 'Avbruten',
|
||||||
@@ -181,26 +175,22 @@ const sv: Translation = {
|
|||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Upp/Nedladdning',
|
UPLOAD_DOWNLOAD: 'Upp/Nedladdning',
|
||||||
VERSION_ON: 'You are currently on', // TODO translate
|
VERSION_ON: 'You are currently on', // TODO translate
|
||||||
SYSTEM_APPLY_FIRMWARE: 'för att aktivera ny firmware',
|
|
||||||
CLOSE: 'Stäng',
|
CLOSE: 'Stäng',
|
||||||
USE: 'Använd',
|
USE: 'Använd',
|
||||||
FACTORY_RESET: 'Fabriksåterställning',
|
FACTORY_RESET: 'Fabriksåterställning',
|
||||||
SYSTEM_FACTORY_TEXT: 'Enheten har blivit fabriksåterställd och startar nu om',
|
SYSTEM_FACTORY_TEXT: 'Enheten har blivit fabriksåterställd och startar nu om',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?',
|
||||||
VERSION_CHECK: 'Senaste versioner',
|
|
||||||
THE_LATEST: 'Den senaste',
|
THE_LATEST: 'Den senaste',
|
||||||
OFFICIAL: 'officiell',
|
OFFICIAL: 'officiell',
|
||||||
DEVELOPMENT: 'utveckling',
|
DEVELOPMENT: 'utveckling',
|
||||||
RELEASE_IS: 'release är', // TODO translate
|
RELEASE_IS: 'release är', // TODO translate
|
||||||
RELEASE_NOTES: 'release-logg',
|
RELEASE_NOTES: 'release-logg',
|
||||||
EMS_ESP_VER: 'EMS-ESP Version',
|
EMS_ESP_VER: 'EMS-ESP Version',
|
||||||
PLATFORM: 'Enhet (Plattform / SDK)',
|
|
||||||
UPTIME: 'Systemets Upptid',
|
UPTIME: 'Systemets Upptid',
|
||||||
CPU_FREQ: 'CPU-frekvens',
|
|
||||||
HEAP: 'Heap (Ledigt / Max allokerat)',
|
HEAP: 'Heap (Ledigt / Max allokerat)',
|
||||||
PSRAM: 'PSRAM (Storlek / Ledigt)',
|
PSRAM: 'PSRAM (Storlek / Ledigt)',
|
||||||
FLASH: 'Flashminne (Storlek / Hastighet)',
|
FLASH: 'Flashminne (Storlek / Hastighet)',
|
||||||
APPSIZE: 'Applikationer (Använt / Ledigt)',
|
APPSIZE: 'Applikationer (Partition: Använt / Ledigt)',
|
||||||
FILESYSTEM: 'Filsystem (Använt / Ledigt)',
|
FILESYSTEM: 'Filsystem (Använt / Ledigt)',
|
||||||
BUFFER_SIZE: 'Max Bufferstorlek',
|
BUFFER_SIZE: 'Max Bufferstorlek',
|
||||||
COMPACT: 'Komprimera',
|
COMPACT: 'Komprimera',
|
||||||
@@ -230,7 +220,7 @@ const sv: Translation = {
|
|||||||
BROKER: 'Broker',
|
BROKER: 'Broker',
|
||||||
CLIENT: 'Client',
|
CLIENT: 'Client',
|
||||||
BASE_TOPIC: 'Base',
|
BASE_TOPIC: 'Base',
|
||||||
OPTIONAL: 'Valfritt',
|
OPTIONAL: 'valfritt',
|
||||||
FORMATTING: 'Formatering',
|
FORMATTING: 'Formatering',
|
||||||
MQTT_FORMAT: 'Topic/Payload Format',
|
MQTT_FORMAT: 'Topic/Payload Format',
|
||||||
MQTT_NEST_1: 'Nestlat i en topic.',
|
MQTT_NEST_1: 'Nestlat i en topic.',
|
||||||
@@ -246,6 +236,7 @@ const sv: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Termostater',
|
MQTT_INT_THERMOSTATS: 'Termostater',
|
||||||
MQTT_INT_SOLAR: 'Solpaneler',
|
MQTT_INT_SOLAR: 'Solpaneler',
|
||||||
MQTT_INT_MIXER: 'Blandningsventiler',
|
MQTT_INT_MIXER: 'Blandningsventiler',
|
||||||
|
MQTT_INT_WATER: 'Water Modules', // TODO translate
|
||||||
MQTT_QUEUE: 'MQTT-kö',
|
MQTT_QUEUE: 'MQTT-kö',
|
||||||
DEFAULT: 'Standard',
|
DEFAULT: 'Standard',
|
||||||
MQTT_ENTITY_FORMAT: 'Entitets-ID format',
|
MQTT_ENTITY_FORMAT: 'Entitets-ID format',
|
||||||
@@ -282,6 +273,7 @@ const sv: Translation = {
|
|||||||
NETWORK_SCANNER: 'Hittade nätverk',
|
NETWORK_SCANNER: 'Hittade nätverk',
|
||||||
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
||||||
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate
|
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate
|
||||||
|
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Värdnamn',
|
HOSTNAME: 'Värdnamn',
|
||||||
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
||||||
@@ -322,7 +314,17 @@ const sv: Translation = {
|
|||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
||||||
|
ENABLE_TLS: 'Aktivera TLS',
|
||||||
|
ON: 'On', // TODO translate
|
||||||
|
OFF: 'Off', // TODO translate
|
||||||
|
POLARITY: 'Polarity', // TODO translate
|
||||||
|
ACTIVEHIGH: 'Active High', // TODO translate
|
||||||
|
ACTIVELOW: 'Active Low', // TODO translate
|
||||||
|
UNCHANGED: 'Unchanged', // TODO translate
|
||||||
|
ALWAYS: 'Always', // TODO translate
|
||||||
|
ACTIVITY: 'Activity', // TODO translate
|
||||||
|
CONFIGURE: 'Configure {0}' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user