mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-03-20 00:26:31 +03:00
Compare commits
896 Commits
v3.7.2
...
2b2c86ba5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b2c86ba5a | ||
|
|
2b2217e8ce | ||
|
|
08d3e8bab6 | ||
|
|
ded3552873 | ||
|
|
9a7893e99f | ||
|
|
307ef4e285 | ||
|
|
f75deb3505 | ||
|
|
6281f9cfe1 | ||
|
|
70810b5e71 | ||
|
|
82cc91cb63 | ||
|
|
48a3fc5656 | ||
|
|
9d20eef12d | ||
|
|
d59e183415 | ||
|
|
50396a5def | ||
|
|
ab92d07716 | ||
|
|
9172dd9181 | ||
|
|
0852502f52 | ||
|
|
c3d066650c | ||
|
|
172e8d0028 | ||
|
|
812c6ac475 | ||
|
|
f7c1f0b0d0 | ||
|
|
125190a0ac | ||
|
|
35c7349e5c | ||
|
|
d7e916269d | ||
|
|
f5f78182b6 | ||
|
|
87bcd4598a | ||
|
|
21a814b5ec | ||
|
|
687d9a40c9 | ||
|
|
9d01791fcb | ||
|
|
028afbe85d | ||
|
|
4bdea56d78 | ||
|
|
bf0737aab8 | ||
|
|
42d879a87b | ||
|
|
79b5671533 | ||
|
|
f48d67d9e7 | ||
|
|
16f7a454db | ||
|
|
02b486ea80 | ||
|
|
61d50e2c79 | ||
|
|
a5af36e15b | ||
|
|
e11ba9e657 | ||
|
|
878f0702b2 | ||
|
|
fa711373f2 | ||
|
|
e9a4a33942 | ||
|
|
f445f36eb1 | ||
|
|
148124ef04 | ||
|
|
27fbafbe62 | ||
|
|
a949673539 | ||
|
|
32193e3c62 | ||
|
|
5f79f0848f | ||
|
|
4d91128aed | ||
|
|
6f1d507df9 | ||
|
|
9b50306172 | ||
|
|
0fbc8e2420 | ||
|
|
f0d162554b | ||
|
|
d92361a8bb | ||
|
|
13bf2c44e7 | ||
|
|
cd155ba680 | ||
|
|
2a565dc677 | ||
|
|
9bf57c3e22 | ||
|
|
766281d8d2 | ||
|
|
bd128072c0 | ||
|
|
88e4ba7ecf | ||
|
|
96e5251050 | ||
|
|
187b163ffd | ||
|
|
9d04058984 | ||
|
|
12b06aa657 | ||
|
|
47b3e4bf00 | ||
|
|
f0f40bbcac | ||
|
|
036e2917a5 | ||
|
|
d294c418c1 | ||
|
|
40da7572cd | ||
|
|
532dc66282 | ||
|
|
8913f38fd0 | ||
|
|
11782eef8b | ||
|
|
b5f4eb6c62 | ||
|
|
ee4f58ce20 | ||
|
|
0fe0ee77b3 | ||
|
|
74e58aaa3d | ||
|
|
d39d6c7f1f | ||
|
|
4043eaf271 | ||
|
|
73ac60a8b2 | ||
|
|
1d6b283033 | ||
|
|
08ca4e44e8 | ||
|
|
255c173469 | ||
|
|
aeee318cca | ||
|
|
eb14e89c35 | ||
|
|
8411ea6773 | ||
|
|
015110a72e | ||
|
|
dae345f359 | ||
|
|
4cfd9b699c | ||
|
|
bd6371fd9d | ||
|
|
7507596869 | ||
|
|
5d99bd923b | ||
|
|
7402776248 | ||
|
|
8b5cc82df9 | ||
|
|
7c5351f15f | ||
|
|
b29f02e5dd | ||
|
|
e9e7162bcd | ||
|
|
b24aae9123 | ||
|
|
9dbd634322 | ||
|
|
daffc94c7f | ||
|
|
93de0e2f42 | ||
|
|
145172b6e9 | ||
|
|
c4a2f8bac8 | ||
|
|
0c0c928efc | ||
|
|
4d829b0b78 | ||
|
|
01e7d9b027 | ||
|
|
439da1d1e9 | ||
|
|
ac45c17204 | ||
|
|
cd24c7815b | ||
|
|
9665efbf38 | ||
|
|
d8aafdbfd4 | ||
|
|
0c6aef5b60 | ||
|
|
48a1bd0fe6 | ||
|
|
44cfffe8a4 | ||
|
|
e75bf8871e | ||
|
|
22703f4100 | ||
|
|
c066ab8400 | ||
|
|
4a0625e31c | ||
|
|
9aaaba5bb7 | ||
|
|
689a3a9a69 | ||
|
|
391a312f0c | ||
|
|
f782eac0cf | ||
|
|
d88513d789 | ||
|
|
59d07e81d6 | ||
|
|
419fe8ef5d | ||
|
|
4cfcba18ee | ||
|
|
b1d6ab3c96 | ||
|
|
ae26754bc8 | ||
|
|
61c3b47269 | ||
|
|
50bedb2b39 | ||
|
|
13db83a6de | ||
|
|
ec43a07866 | ||
|
|
fbc11b8ef8 | ||
|
|
f1c5a911f9 | ||
|
|
76c0aa6be8 | ||
|
|
61bf2332bb | ||
|
|
39ca956e1f | ||
|
|
0683b77437 | ||
|
|
5da2760dc6 | ||
|
|
3fabaf900f | ||
|
|
b2a8738672 | ||
|
|
c3b9c1ef98 | ||
|
|
aef6b6e92d | ||
|
|
dc46dac02a | ||
|
|
025c430611 | ||
|
|
995ab7233d | ||
|
|
1507989ca3 | ||
|
|
022e808b14 | ||
|
|
9b604e9c78 | ||
|
|
cd3cc09386 | ||
|
|
0df21a7843 | ||
|
|
9225ad2ad9 | ||
|
|
227b1ac59b | ||
|
|
a9a6e32dd1 | ||
|
|
3c4278029f | ||
|
|
3b4e09208e | ||
|
|
e9e0688737 | ||
|
|
7bb1b7bb91 | ||
|
|
4302bc9978 | ||
|
|
60d884df88 | ||
|
|
177c635bc1 | ||
|
|
9a97c28bf0 | ||
|
|
deb87cf5d7 | ||
|
|
a50227638b | ||
|
|
92b1515c8a | ||
|
|
0c5cf0475c | ||
|
|
f26e937514 | ||
|
|
1e4ca8b57f | ||
|
|
4d88bbd28f | ||
|
|
0ce110df9e | ||
|
|
3759fc81ba | ||
|
|
7965ecd856 | ||
|
|
7b0169bb68 | ||
|
|
f10f3d5305 | ||
|
|
ed9e2704b0 | ||
|
|
c47dd0e523 | ||
|
|
80c75bae77 | ||
|
|
cfa973b08b | ||
|
|
83987b71e0 | ||
|
|
a318f34988 | ||
|
|
5cc1660675 | ||
|
|
8a48da38b8 | ||
|
|
d514e67eb8 | ||
|
|
69964482f8 | ||
|
|
2aa691212c | ||
|
|
c27134f185 | ||
|
|
c8033692b1 | ||
|
|
c537d0ab8b | ||
|
|
bee703eb1f | ||
|
|
5d2bd6a2af | ||
|
|
67f0f40a8a | ||
|
|
e796fbef7a | ||
|
|
da7ef04741 | ||
|
|
ddb318dfc6 | ||
|
|
88643dc8e3 | ||
|
|
cf3854563d | ||
|
|
4b2468d616 | ||
|
|
4b08aba9c4 | ||
|
|
0a18add447 | ||
|
|
ca8d23ff3a | ||
|
|
c7e833194f | ||
|
|
f63f658421 | ||
|
|
13fcf09470 | ||
|
|
f560cbd60c | ||
|
|
38ead7e10f | ||
|
|
326bba9b42 | ||
|
|
d9a18bf255 | ||
|
|
6c42cbfb4b | ||
|
|
6691c81956 | ||
|
|
2f95ef305d | ||
|
|
7afde0ce6e | ||
|
|
f3cdafe7d0 | ||
|
|
4bf23e1bda | ||
|
|
aca66457f9 | ||
|
|
121887bdce | ||
|
|
32d7cf4e9c | ||
|
|
3f8227e95e | ||
|
|
10d84261da | ||
|
|
51848d8347 | ||
|
|
1c0669144f | ||
|
|
41a2ba6e5d | ||
|
|
b6fe9e7569 | ||
|
|
faa2c5f1aa | ||
|
|
c71034ff12 | ||
|
|
71be615bbe | ||
|
|
ce53fd1d04 | ||
|
|
1772876f9e | ||
|
|
cd5dbebea9 | ||
|
|
6c67b78a1c | ||
|
|
9b4deb271b | ||
|
|
0e9283af5c | ||
|
|
58011700fe | ||
|
|
079a08ff7b | ||
|
|
b64a55e460 | ||
|
|
2b7ef5b6ba | ||
|
|
d62eef4eca | ||
|
|
0f6d6e69f5 | ||
|
|
97f689b8a7 | ||
|
|
be9b4a070c | ||
|
|
bc15dd4463 | ||
|
|
1613caea86 | ||
|
|
4b39ab76ab | ||
|
|
d04c882590 | ||
|
|
a199bf21e1 | ||
|
|
3ae8722ece | ||
|
|
6a6cef57cf | ||
|
|
090491aab6 | ||
|
|
ca81a02a8c | ||
|
|
f64188bd5d | ||
|
|
d3e0f180c5 | ||
|
|
3f4d87a1d2 | ||
|
|
1d89e651a4 | ||
|
|
fad67b4ef9 | ||
|
|
ce1c22ee35 | ||
|
|
169b5f34ea | ||
|
|
131c03714f | ||
|
|
024c4a0c21 | ||
|
|
b0d111d86f | ||
|
|
faeef9c821 | ||
|
|
60a5b28a21 | ||
|
|
f4b5cf04a0 | ||
|
|
d69f26acac | ||
|
|
2a50701107 | ||
|
|
ab099c45b8 | ||
|
|
47f21019a0 | ||
|
|
5c473c2b3d | ||
|
|
9ddc587334 | ||
|
|
9b0a7a4872 | ||
|
|
97528e9df6 | ||
|
|
b797e1e2bb | ||
|
|
bb52d35c99 | ||
|
|
4c9026e11a | ||
|
|
6cd4e8a5b6 | ||
|
|
dfe037a7d3 | ||
|
|
b87622185d | ||
|
|
0318f8156d | ||
|
|
0c03fa1308 | ||
|
|
2d6e02171f | ||
|
|
2da312bf15 | ||
|
|
52f59a7b1d | ||
|
|
6c8624298c | ||
|
|
ce2d2fb867 | ||
|
|
ba2ad4e175 | ||
|
|
b3320c3e48 | ||
|
|
dc1094b6ba | ||
|
|
bb60568d83 | ||
|
|
67b5c5dd26 | ||
|
|
6866d5b7a9 | ||
|
|
b4e9af89ee | ||
|
|
775ed99b22 | ||
|
|
2ec13273fd | ||
|
|
a846b01103 | ||
|
|
6dffb08545 | ||
|
|
16f7cc148d | ||
|
|
568431ada4 | ||
|
|
6034c1e5eb | ||
|
|
e3566feefb | ||
|
|
ea46c79278 | ||
|
|
a02831e04e | ||
|
|
3b8c973f2a | ||
|
|
2c65936b3e | ||
|
|
bc04c34d58 | ||
|
|
5047f1752e | ||
|
|
1fa7a6c549 | ||
|
|
f9ebe33a7d | ||
|
|
e719dd963d | ||
|
|
c6b0099581 | ||
|
|
71726530c0 | ||
|
|
a749ecb298 | ||
|
|
7e963529c4 | ||
|
|
c76409cf3f | ||
|
|
efd0872690 | ||
|
|
57098b578f | ||
|
|
6472e9e224 | ||
|
|
026828efc7 | ||
|
|
fe6e9be4d3 | ||
|
|
7745a6f9a1 | ||
|
|
c523a379fe | ||
|
|
2854e9cbe9 | ||
|
|
4985f104c7 | ||
|
|
a0ea5f7ea1 | ||
|
|
efc35d0594 | ||
|
|
ccd6c6f8ad | ||
|
|
b426e0eb45 | ||
|
|
c53e1de569 | ||
|
|
8058e98748 | ||
|
|
ba419d09eb | ||
|
|
c701247652 | ||
|
|
12754d1c07 | ||
|
|
9a4daba31a | ||
|
|
a2aa2dccdd | ||
|
|
25af51a8e8 | ||
|
|
ddc597ff03 | ||
|
|
75310afd63 | ||
|
|
3095323c93 | ||
|
|
4667718f12 | ||
|
|
2cb1c5d7e7 | ||
|
|
d7b9754ddb | ||
|
|
99b769626e | ||
|
|
70035b059c | ||
|
|
b252c2f95a | ||
|
|
baa4f2eb39 | ||
|
|
c7b970b5b0 | ||
|
|
3ed5b65191 | ||
|
|
6e01c00d46 | ||
|
|
e72afc9065 | ||
|
|
de2f3e712d | ||
|
|
cacb92cd47 | ||
|
|
3eb20fa700 | ||
|
|
d35574d494 | ||
|
|
3cb29220ab | ||
|
|
d91812ab8f | ||
|
|
856f8efd25 | ||
|
|
d32378ccd4 | ||
|
|
f5006d1a11 | ||
|
|
c3468e6308 | ||
|
|
9f4de56099 | ||
|
|
78738de811 | ||
|
|
e64596ad61 | ||
|
|
024357ae80 | ||
|
|
3f07d3b75f | ||
|
|
cb7c695c67 | ||
|
|
912a764c2d | ||
|
|
c9c0f55b64 | ||
|
|
6991677cf9 | ||
|
|
83330907cd | ||
|
|
3571998da3 | ||
|
|
77465ebe81 | ||
|
|
006e5493e2 | ||
|
|
b29136433d | ||
|
|
0347a4b8b0 | ||
|
|
3330103a8d | ||
|
|
0a02252fee | ||
|
|
642f2116d2 | ||
|
|
7b8e45c2f7 | ||
|
|
0f2244607f | ||
|
|
32ab9dda45 | ||
|
|
b6659b8586 | ||
|
|
5eb85066ef | ||
|
|
9398fc72a0 | ||
|
|
1bcd453e3f | ||
|
|
d405478a13 | ||
|
|
c927e5f496 | ||
|
|
c5dbd7452e | ||
|
|
3a0b4ea587 | ||
|
|
6f4cdb7122 | ||
|
|
b5d6757660 | ||
|
|
0dcde46296 | ||
|
|
ac7e91beff | ||
|
|
9ea1e2752d | ||
|
|
b5471aef94 | ||
|
|
f31329ceff | ||
|
|
40d48f4407 | ||
|
|
11b7e1f86e | ||
|
|
e364a71eda | ||
|
|
e006bebb86 | ||
|
|
fa3d42a1c7 | ||
|
|
e435fd4391 | ||
|
|
d42efb32ab | ||
|
|
ad8f2dc823 | ||
|
|
f2ff14f511 | ||
|
|
e5e9d4c713 | ||
|
|
4c5f93000b | ||
|
|
0c7301a020 | ||
|
|
74c63bf17e | ||
|
|
4564e0b828 | ||
|
|
2ab9607989 | ||
|
|
29d198b46d | ||
|
|
8387ca0c07 | ||
|
|
3796fb8027 | ||
|
|
1da08633ec | ||
|
|
b097e372e4 | ||
|
|
846776929e | ||
|
|
6e1d56b8ee | ||
|
|
32f7eb7299 | ||
|
|
3fc9c3b56c | ||
|
|
e2e46543d2 | ||
|
|
a2b22198ec | ||
|
|
642b59f729 | ||
|
|
9e81de2164 | ||
|
|
d44797db1d | ||
|
|
673ee3f79b | ||
|
|
38a8179544 | ||
|
|
cfb59ac6a0 | ||
|
|
80c26e1adb | ||
|
|
d0de6e8d0f | ||
|
|
68be7d00ff | ||
|
|
d3e6043911 | ||
|
|
373895b36a | ||
|
|
594e10dbe1 | ||
|
|
e3c5b462da | ||
|
|
8a1376b169 | ||
|
|
900e26cf9f | ||
|
|
071e81f29b | ||
|
|
d1bd861ff0 | ||
|
|
f5925dbb3b | ||
|
|
b1eedcb1d8 | ||
|
|
ed7a9f43de | ||
|
|
67885950ef | ||
|
|
74ddb771e9 | ||
|
|
584d0e0b48 | ||
|
|
8d9ca33ea3 | ||
|
|
f0eea1a6a3 | ||
|
|
79cc0377c0 | ||
|
|
115cec08fa | ||
|
|
6df592c2b8 | ||
|
|
f2b81489ba | ||
|
|
0d8760219a | ||
|
|
e8e8d9c130 | ||
|
|
8f712412f5 | ||
|
|
f8ece46163 | ||
|
|
cd8b1add54 | ||
|
|
1c415a9715 | ||
|
|
e1e3601640 | ||
|
|
c2f718b49a | ||
|
|
cee1874689 | ||
|
|
57d172aac2 | ||
|
|
bb26900213 | ||
|
|
9d1ee27533 | ||
|
|
7fd735f667 | ||
|
|
2e79c3a5c6 | ||
|
|
d769999f10 | ||
|
|
bd93d26361 | ||
|
|
72feefe709 | ||
|
|
1d6c2c9664 | ||
|
|
85c78bc8e9 | ||
|
|
18bdcfe050 | ||
|
|
a6f77250b5 | ||
|
|
9874ecde82 | ||
|
|
584b8788be | ||
|
|
7eb15652c7 | ||
|
|
2c28a607ba | ||
|
|
45eca462e7 | ||
|
|
4474868afc | ||
|
|
6c6b5b060d | ||
|
|
c03eb290d1 | ||
|
|
de9bd44071 | ||
|
|
b7458b0686 | ||
|
|
a660ec1afa | ||
|
|
c4f6f01f7e | ||
|
|
9f60560f2b | ||
|
|
7b50f80cb8 | ||
|
|
656d275c56 | ||
|
|
eca17f2b2c | ||
|
|
7f60279aa3 | ||
|
|
5227fafa1b | ||
|
|
4991e2b7cd | ||
|
|
34c514709a | ||
|
|
7dfedfeb10 | ||
|
|
c8bf4cae17 | ||
|
|
2818e268b6 | ||
|
|
7a95c11f62 | ||
|
|
d712b1cce9 | ||
|
|
03fa92352b | ||
|
|
e121fdb47f | ||
|
|
c05793f64f | ||
|
|
3836610d81 | ||
|
|
c3f87cd321 | ||
|
|
4d5a27f45e | ||
|
|
c37c1aaad5 | ||
|
|
110c0df6fb | ||
|
|
04ac3be242 | ||
|
|
44c4ee8bc0 | ||
|
|
57c4d550a3 | ||
|
|
4bcb95eece | ||
|
|
0a92d455c8 | ||
|
|
edb30931ae | ||
|
|
d03ab7a16f | ||
|
|
ea9b6b3e00 | ||
|
|
bae6b600bd | ||
|
|
7eac920985 | ||
|
|
00c2b5992c | ||
|
|
43d2fa1f00 | ||
|
|
92d40d9287 | ||
|
|
7a47a2090f | ||
|
|
0d98491a97 | ||
|
|
16cf16616e | ||
|
|
d9f56ef3ae | ||
|
|
c8934af9bb | ||
|
|
cbacaa98d9 | ||
|
|
f1b6a0baf3 | ||
|
|
4d15f48e2b | ||
|
|
2ffd00e28a | ||
|
|
8ef5be9a7f | ||
|
|
8769faeb83 | ||
|
|
cefbf2d4d6 | ||
|
|
bfd5082054 | ||
|
|
3d3a634d94 | ||
|
|
1cb078cd3c | ||
|
|
22683f5d12 | ||
|
|
57b42aa7c2 | ||
|
|
4a59743024 | ||
|
|
66cec18dee | ||
|
|
ad71938fde | ||
|
|
d4155d6e9e | ||
|
|
af6be4c6b1 | ||
|
|
cfbd0168c3 | ||
|
|
61b9bd7581 | ||
|
|
4c7ad7124e | ||
|
|
0413314cfb | ||
|
|
ab7cbe8ead | ||
|
|
d1264828eb | ||
|
|
76a317b5c0 | ||
|
|
ec11ae2ef7 | ||
|
|
b857c6eb44 | ||
|
|
3f8add73ac | ||
|
|
08b0ddbb7f | ||
|
|
c44cb7e7fd | ||
|
|
77ff61046e | ||
|
|
a8eb06bef2 | ||
|
|
566b5c8ea5 | ||
|
|
eeccd076a0 | ||
|
|
f45ac9d0ef | ||
|
|
cdd9acddfa | ||
|
|
e484f11d12 | ||
|
|
19572f313a | ||
|
|
af9ad5d624 | ||
|
|
8adca69140 | ||
|
|
01710316ed | ||
|
|
ab80c82a22 | ||
|
|
dceafe65a7 | ||
|
|
4734a81fdb | ||
|
|
a2c099e615 | ||
|
|
f9b88a1b6b | ||
|
|
7f2b8cc971 | ||
|
|
582fb3d72f | ||
|
|
bf4fa74742 | ||
|
|
c62b3b9864 | ||
|
|
0ae9795d6b | ||
|
|
7488c31cd3 | ||
|
|
dc0e634004 | ||
|
|
57e7c0ae4f | ||
|
|
7214acfa20 | ||
|
|
ff6d47bb9c | ||
|
|
81971ba53f | ||
|
|
a58f37e3eb | ||
|
|
09a746cf8e | ||
|
|
ea70119138 | ||
|
|
5a9c5b5e2d | ||
|
|
7fb09c5045 | ||
|
|
705171f305 | ||
|
|
400d1a5f1a | ||
|
|
c4855cc5f2 | ||
|
|
1e4b487299 | ||
|
|
cbd883103e | ||
|
|
2ce12943cd | ||
|
|
4151a82b3b | ||
|
|
b871081ef1 | ||
|
|
da51d1d7d9 | ||
|
|
82dae30224 | ||
|
|
1fdac2fdab | ||
|
|
56b23e27d7 | ||
|
|
ba29aa62d3 | ||
|
|
be2342285f | ||
|
|
5595c01221 | ||
|
|
133cddef5b | ||
|
|
0fdba1f84d | ||
|
|
e10ec26e79 | ||
|
|
ffbb397dba | ||
|
|
799076d0c4 | ||
|
|
1fbd10df27 | ||
|
|
4a2f82f1e8 | ||
|
|
d913e4d90b | ||
|
|
0958c29c9e | ||
|
|
36e1c9f79d | ||
|
|
8fedac53dd | ||
|
|
a1c6159fc5 | ||
|
|
5b33acba5e | ||
|
|
4abaef2943 | ||
|
|
ad71773293 | ||
|
|
5b07309939 | ||
|
|
7a044a1dcd | ||
|
|
6507764157 | ||
|
|
7dfa8fc883 | ||
|
|
6df7965bb2 | ||
|
|
02a3dee764 | ||
|
|
d5895f1710 | ||
|
|
2b90ad3f6d | ||
|
|
0bb61b4296 | ||
|
|
2378fb547c | ||
|
|
a79ff3f417 | ||
|
|
4bc93615c5 | ||
|
|
685f0d93e5 | ||
|
|
1d7b6674bb | ||
|
|
014405e451 | ||
|
|
aff3ca3ad3 | ||
|
|
b723d09952 | ||
|
|
bfff842c82 | ||
|
|
ad7d21764d | ||
|
|
f2ae84b004 | ||
|
|
a81956654e | ||
|
|
3cb662799f | ||
|
|
9188d03d61 | ||
|
|
3df2d36453 | ||
|
|
0ab7eb42e4 | ||
|
|
84d4fb37fa | ||
|
|
aa9b38da03 | ||
|
|
8342867807 | ||
|
|
d8cff865da | ||
|
|
096f7e1c88 | ||
|
|
0608d847f5 | ||
|
|
b20360c2a5 | ||
|
|
59b5086cab | ||
|
|
2e3024ab61 | ||
|
|
b5299719da | ||
|
|
2620f56e0d | ||
|
|
20b978c46c | ||
|
|
5c8a18df68 | ||
|
|
3464d6c324 | ||
|
|
eac0cc0521 | ||
|
|
0953d37303 | ||
|
|
1d3fec2a95 | ||
|
|
61b374b7c0 | ||
|
|
c47cc0d5f1 | ||
|
|
939882efbf | ||
|
|
f42cbf548e | ||
|
|
91075ace37 | ||
|
|
de6405f8d1 | ||
|
|
2ffcaf4a9e | ||
|
|
1bda62309b | ||
|
|
83659e5da8 | ||
|
|
a6e136561e | ||
|
|
a75d7487fc | ||
|
|
31b0dd8d58 | ||
|
|
696bd1f455 | ||
|
|
18355efde2 | ||
|
|
d5100134e4 | ||
|
|
b932242e04 | ||
|
|
73ccff3412 | ||
|
|
e5f852a7ed | ||
|
|
581f19462d | ||
|
|
eb59b37251 | ||
|
|
f3696f60cd | ||
|
|
6b4e21f5db | ||
|
|
3d4d5b7bbc | ||
|
|
e6f15681c0 | ||
|
|
5f52a646ff | ||
|
|
be4f9296a5 | ||
|
|
c3181f589c | ||
|
|
872cd40f56 | ||
|
|
30b9de49bf | ||
|
|
8a91c6eb2f | ||
|
|
243471e21d | ||
|
|
b8f97ec94d | ||
|
|
8576a6f253 | ||
|
|
b33e6ceca9 | ||
|
|
8eaf7f32cd | ||
|
|
becdc8cef5 | ||
|
|
651688219c | ||
|
|
b9a4bb3511 | ||
|
|
b318274129 | ||
|
|
8b0e5ba8e7 | ||
|
|
4a9b74b311 | ||
|
|
371b198eb6 | ||
|
|
a6dfdb2c4c | ||
|
|
3122c2b2a9 | ||
|
|
9ac8d149fb | ||
|
|
91e1b0b3b8 | ||
|
|
01636ced88 | ||
|
|
53e587537f | ||
|
|
77eeacf121 | ||
|
|
a89c42d659 | ||
|
|
ba4bc423f4 | ||
|
|
8cd341576d | ||
|
|
006eae5862 | ||
|
|
6e29de4463 | ||
|
|
92d816b990 | ||
|
|
37ad1968b5 | ||
|
|
01793dd4f6 | ||
|
|
9a7f7fa1d5 | ||
|
|
648675d002 | ||
|
|
462d865fc9 | ||
|
|
9f24851948 | ||
|
|
a5e5ec5098 | ||
|
|
db90546bc3 | ||
|
|
2d9ea3ee8d | ||
|
|
4d3cafcf29 | ||
|
|
8685ffb1bf | ||
|
|
86408b3452 | ||
|
|
eab94f3b84 | ||
|
|
9123dbcc9e | ||
|
|
ec6f426b06 | ||
|
|
5482937332 | ||
|
|
0b667703c2 | ||
|
|
c732c96fc2 | ||
|
|
e3d260429c | ||
|
|
77eb2c747b | ||
|
|
6853cd738f | ||
|
|
d58776beab | ||
|
|
94a7b1e438 | ||
|
|
c3f7540f74 | ||
|
|
4642a50f69 | ||
|
|
b23bcf3f0b | ||
|
|
570678e3d3 | ||
|
|
64a2f5eb11 | ||
|
|
24fba8b382 | ||
|
|
9339ef481a | ||
|
|
075789b902 | ||
|
|
1dd1b47faf | ||
|
|
525a164c69 | ||
|
|
b60f333edb | ||
|
|
2323fdfe56 | ||
|
|
9b7fed4d1f | ||
|
|
67c59c9b4b | ||
|
|
b5fea921e6 | ||
|
|
eeb071afc6 | ||
|
|
5669873101 | ||
|
|
d371c9bc82 | ||
|
|
153dd19fc6 | ||
|
|
ae258a75d9 | ||
|
|
37c4be321f | ||
|
|
c810d58064 | ||
|
|
5a27817d11 | ||
|
|
4be2f9283d | ||
|
|
a65162fbbc | ||
|
|
494cf3b6a8 | ||
|
|
b900194402 | ||
|
|
d6e72e72d7 | ||
|
|
960baadeca | ||
|
|
ed92b37869 | ||
|
|
1598809815 | ||
|
|
3131969fc1 | ||
|
|
fb44bc33b9 | ||
|
|
59a806ac8c | ||
|
|
6a2a27e47e | ||
|
|
251d0af028 | ||
|
|
8fa800e2f7 | ||
|
|
df9d20ad88 | ||
|
|
c07754047d | ||
|
|
9c00af317e | ||
|
|
d3d132ec45 | ||
|
|
7adba972e7 | ||
|
|
d83399bd1f | ||
|
|
4471da4aa9 | ||
|
|
b3be1d9351 | ||
|
|
c6b8c2a630 | ||
|
|
3f51c21dc7 | ||
|
|
a8cdbc4fd6 | ||
|
|
95e5babb13 | ||
|
|
74cb23a8bb | ||
|
|
6be304f295 | ||
|
|
e702b0b733 | ||
|
|
bfbd263c74 | ||
|
|
472f922369 | ||
|
|
b13c608ff3 | ||
|
|
5464909121 | ||
|
|
d874b3f808 | ||
|
|
92108bc743 | ||
|
|
66ca1e52bb | ||
|
|
3589094d06 | ||
|
|
801ed6ef79 | ||
|
|
2547ae45a8 | ||
|
|
93e4abe72d | ||
|
|
eb87651c47 | ||
|
|
4138598db2 | ||
|
|
913bbd6e3b | ||
|
|
d35881b05b | ||
|
|
33b54ccf12 | ||
|
|
a8775b2200 | ||
|
|
6d3746222d | ||
|
|
fe169ac80f | ||
|
|
83724e3d44 | ||
|
|
a4db3ef5c4 | ||
|
|
f8adad7865 | ||
|
|
12c094228e | ||
|
|
902ea80807 | ||
|
|
73831d9ac6 | ||
|
|
6bfda79441 | ||
|
|
112de78fc5 | ||
|
|
adbd2381e1 | ||
|
|
397f3f546e | ||
|
|
43d3c28e16 | ||
|
|
747a64b869 | ||
|
|
7c2e5560bd | ||
|
|
9194db9f70 | ||
|
|
fece00c0c6 | ||
|
|
ba3ae5ea56 | ||
|
|
4c69c9e445 | ||
|
|
97925c47fd | ||
|
|
ad89fe15b1 | ||
|
|
29035cabfe | ||
|
|
9b3d43d27f | ||
|
|
0b4f17473a | ||
|
|
b0c29b57c7 | ||
|
|
6d22f6aebf | ||
|
|
3e3e10e6a0 | ||
|
|
b854c777c8 | ||
|
|
b71fdd77e8 | ||
|
|
0f6f7cea19 | ||
|
|
58beb092c2 | ||
|
|
c3f200f73b | ||
|
|
98640c11b1 | ||
|
|
d7904bdcaf | ||
|
|
ce05a94d58 | ||
|
|
c0ed62dc7a | ||
|
|
1557fa98b1 | ||
|
|
81a530f153 | ||
|
|
a4733c3e6a | ||
|
|
7851b8e94c | ||
|
|
36838f7690 | ||
|
|
fdd87d0757 | ||
|
|
c8822aff64 | ||
|
|
4b3205fc9c | ||
|
|
afc05ae9e8 | ||
|
|
9c3044efa0 | ||
|
|
8caeb129c1 | ||
|
|
0427504f0e | ||
|
|
4f11a7caa1 | ||
|
|
150695c185 | ||
|
|
3558591480 | ||
|
|
f7a24052c2 | ||
|
|
75c452486c | ||
|
|
40cab6775c | ||
|
|
392829c7db | ||
|
|
4621c9d616 | ||
|
|
006d664ec9 | ||
|
|
0cc9ac4dd8 | ||
|
|
502096dc22 | ||
|
|
8c424c7a64 | ||
|
|
d7c118b88a | ||
|
|
1fdb0b7516 | ||
|
|
c2fc771756 | ||
|
|
6f759c5bc4 | ||
|
|
facbbf1353 | ||
|
|
a218c7a781 | ||
|
|
5f42709eab | ||
|
|
5ec0f657a0 | ||
|
|
812911ffbb | ||
|
|
55235687ba | ||
|
|
a970009d20 | ||
|
|
4afc16e2cb | ||
|
|
3772d72b43 | ||
|
|
607f949638 | ||
|
|
473cf7c8af | ||
|
|
e0909df06c | ||
|
|
5fc606ef6d | ||
|
|
a3032f4da7 | ||
|
|
7fdd65e8ca | ||
|
|
dc6bf883f1 | ||
|
|
ce5edd93b4 | ||
|
|
e36e6bec9c | ||
|
|
c8fd08b6d2 | ||
|
|
c0d693c1c8 | ||
|
|
5d2a6e2898 | ||
|
|
4547a5ceb0 | ||
|
|
76151c4395 | ||
|
|
481089b1b4 | ||
|
|
463787b7f4 | ||
|
|
e2258a1c43 | ||
|
|
5528f29b6a | ||
|
|
e3861d54c9 | ||
|
|
3368f2803c | ||
|
|
6ca1d68d23 | ||
|
|
cf93081252 | ||
|
|
30fca2a190 |
@@ -1,53 +1,60 @@
|
|||||||
name: 'pre-release'
|
name: 'Build dev release'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- 'src/emsesp_version.h'
|
||||||
branches:
|
branches:
|
||||||
- 'dev'
|
- 'dev'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-release:
|
pre-release:
|
||||||
name: 'Automatic pre-release build'
|
name: 'Build Dev Release'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Enable Corepack
|
|
||||||
run: corepack enable
|
|
||||||
|
|
||||||
- name: Install python 3.11
|
- name: Install python 3.13
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Install Node.js 20
|
- name: Install Node.js 22
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: 22
|
||||||
|
|
||||||
- name: Get EMS-ESP version
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Enable Corepack
|
||||||
|
run: corepack enable pnpm
|
||||||
|
|
||||||
|
- name: Get the EMS-ESP version
|
||||||
id: build_info
|
id: build_info
|
||||||
run: |
|
run: |
|
||||||
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/version.h | awk -F'"' '{print $2}'`
|
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/emsesp_version.h | awk -F'"' '{print $2}'`
|
||||||
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -U platformio
|
pip install -U platformio
|
||||||
|
python -m pip install intelhex
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Build the WebUI
|
||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
pnpm install
|
||||||
yarn typesafe-i18n --no-watch
|
pnpm 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 build
|
pnpm build
|
||||||
yarn webUI
|
pnpm webUI
|
||||||
|
|
||||||
- name: Build all PIO target environments from default_envs
|
- name: Build all PIO target environments
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
env:
|
env:
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
name: 'github-releases-to-discord'
|
name: 'Publish releases to discord'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/pr_check.yml
vendored
2
.github/workflows/pr_check.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: 'pr_check'
|
name: 'Pre-check on PR'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
17
.github/workflows/sonar_check.yml
vendored
17
.github/workflows/sonar_check.yml
vendored
@@ -20,15 +20,12 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Install Build Wrapper
|
||||||
- name: Install sonar-scanner and build-wrapper
|
uses: SonarSource/sonarqube-scan-action/install-build-wrapper@master
|
||||||
uses: SonarSource/sonarcloud-github-c-cpp@v2
|
- name: Run Build Wrapper
|
||||||
|
run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make all
|
||||||
- name: Run build-wrapper
|
- name: SonarQube Scan
|
||||||
run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make all
|
uses: SonarSource/sonarqube-scan-action@master
|
||||||
|
|
||||||
- name: Run sonar-scanner
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
run: sonar-scanner --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
name: 'tagged-release'
|
name: 'Build stable release'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -8,40 +11,42 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tagged-release:
|
tagged-release:
|
||||||
name: 'Tagged Release'
|
name: 'Build Stable Release'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Install python 3.13
|
||||||
run: corepack enable
|
|
||||||
|
|
||||||
- name: Install python 3.11
|
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Install Node.js 20
|
- name: Install Node.js 22
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: 22
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Enable Corepack
|
||||||
|
run: corepack enable pnpm
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -U platformio
|
pip install -U platformio
|
||||||
|
python -m pip install intelhex
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Build the WebUI
|
||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
pnpm install
|
||||||
yarn typesafe-i18n --no-watch
|
pnpm 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 build
|
pnpm build
|
||||||
yarn webUI
|
pnpm webUI
|
||||||
|
|
||||||
- name: Build all PIO target environments from default_envs
|
- name: Build all PIO target environments
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
env:
|
env:
|
||||||
23
.github/workflows/stale_issues.yml
vendored
Normal file
23
.github/workflows/stale_issues.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: "Mark or close stale issues and PRs"
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 1 * * *"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
days-before-stale: 30
|
||||||
|
days-before-close: 5
|
||||||
|
stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment otherwise this will be closed in 5 days."
|
||||||
|
stale-pr-message: "This PR has been automatically marked as stale because there has been no activity in last 30 days. It will be closed if no further activity occurs. Thank you for your contributions."
|
||||||
|
close-issue-message: "This issue was closed because it has been stalled for 5 days with no activity."
|
||||||
|
close-pr-message: "This PR was automatically closed because of being stale."
|
||||||
|
stale-pr-label: "stale"
|
||||||
|
stale-issue-label: "stale"
|
||||||
|
exempt-issue-labels: "bug,enhancement,pinned,security"
|
||||||
|
exempt-pr-labels: "bug,enhancement,pinned,security"
|
||||||
45
.github/workflows/test_release.yml
vendored
45
.github/workflows/test_release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: 'test-release'
|
name: 'Build test release'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -6,46 +6,55 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'dev2'
|
- 'dev2'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-release:
|
pre-release:
|
||||||
name: 'Automatic test-release build'
|
name: 'Build Test Release'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Install python 3.13
|
||||||
run: corepack enable
|
uses: actions/setup-python@v5
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Use Node.js 20.x
|
- name: Install Node.js 22
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: 22
|
||||||
|
|
||||||
- name: Get EMS-ESP source code and version
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Enable Corepack
|
||||||
|
run: corepack enable pnpm
|
||||||
|
|
||||||
|
- name: Get the EMS-ESP version
|
||||||
id: build_info
|
id: build_info
|
||||||
run: |
|
run: |
|
||||||
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/version.h | awk -F'"' '{print $2}'`
|
version=`grep -E '^#define EMSESP_APP_VERSION' ./src/emsesp_version.h | awk -F'"' '{print $2}'`
|
||||||
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
echo "VERSION=$version" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -U platformio
|
pip install -U platformio
|
||||||
|
python -m pip install intelhex
|
||||||
|
|
||||||
- name: Build WebUI
|
- name: Build the WebUI
|
||||||
run: |
|
run: |
|
||||||
cd interface
|
cd interface
|
||||||
yarn install
|
pnpm install
|
||||||
yarn typesafe-i18n --no-watch
|
pnpm 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 build
|
pnpm build
|
||||||
yarn webUI
|
pnpm webUI
|
||||||
|
|
||||||
- name: Build all target environments from default_envs
|
- name: Build all target environments
|
||||||
run: |
|
run: |
|
||||||
platformio run
|
platformio run
|
||||||
env:
|
env:
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -28,14 +28,10 @@ stats.html
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
.pnp.*
|
.pnp.*
|
||||||
*/.yarn/cache/*
|
|
||||||
*/.yarn/install-state.gz
|
|
||||||
analyse.html
|
analyse.html
|
||||||
interface/vite.config.ts.timestamp*
|
interface/vite.config.ts.timestamp*
|
||||||
*.local
|
*.local
|
||||||
src/ESP32React/WWWData.h
|
src/ESP32React/WWWData.h
|
||||||
.yarn/*
|
|
||||||
.yarnrc.yml
|
|
||||||
|
|
||||||
# i18n generated files
|
# i18n generated files
|
||||||
interface/src/i18n/i18n-react.tsx
|
interface/src/i18n/i18n-react.tsx
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
|
|||||||
|
|
||||||
## **IMPORTANT! BREAKING CHANGES**
|
## **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.
|
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
|
## Added
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,56 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
|
||||||
|
|
||||||
|
## [3.7.3]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- analogsensor types: NTC and RGB-Led
|
||||||
|
- Flag for HMC310 [#2465](https://github.com/emsesp/EMS-ESP32/issues/2465)
|
||||||
|
- boiler auxheatersource [#2489](https://github.com/emsesp/EMS-ESP32/discussions/2489)
|
||||||
|
- thermostat last error for RC100/300 [#2501](https://github.com/emsesp/EMS-ESP32/issues/2501)
|
||||||
|
- boiler 0xC6 telegram [#1963](https://github.com/emsesp/EMS-ESP32/issues/1963)
|
||||||
|
- CS6800i changes [#2448](https://github.com/emsesp/EMS-ESP32/issues/2448), [#2449](https://github.com/emsesp/EMS-ESP32/issues/2449)
|
||||||
|
- charging pump [#2544](https://github.com/emsesp/EMS-ESP32/issues/2544)
|
||||||
|
- hybrid CSH5800iG [#2569](https://github.com/emsesp/EMS-ESP32/issues/2569)
|
||||||
|
- add EMS Device details to Home Assistant MQTT Discovery
|
||||||
|
- disinfection command [#2601](https://github.com/emsesp/EMS-ESP32/issues/2601)
|
||||||
|
- added new board profile for upcoming BBQKees E32V2.2
|
||||||
|
- set differential pressure entity in Mixer device
|
||||||
|
- set set climate action cooling/heating in HA [#2583](https://github.com/emsesp/EMS-ESP32/issues/2583)
|
||||||
|
- Internal sensors of E32V2_2
|
||||||
|
- FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610)
|
||||||
|
- CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437)
|
||||||
|
- Fuse settings for BBQKees boards
|
||||||
|
- Analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624)
|
||||||
|
- Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631)
|
||||||
|
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636)
|
||||||
|
- Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645)
|
||||||
|
- RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- dhw/switchtime [#2490](https://github.com/emsesp/EMS-ESP32/issues/2490)
|
||||||
|
- switch to secure mqtt [#2492](https://github.com/emsesp/EMS-ESP32/issues/2492)
|
||||||
|
- update link buttons [#2497](https://github.com/emsesp/EMS-ESP32/issues/2497)
|
||||||
|
- refresh scheduler states [#2502](https://github.com/emsesp/EMS-ESP32/discussions/2502)
|
||||||
|
- also rebuild HA config on mqtt connect for scheduler, custom and shower
|
||||||
|
- FB100 controls the hc, not the master [#2510](https://github.com/emsesp/EMS-ESP32/issues/2510)
|
||||||
|
- IPM DHW module, [#2524](https://github.com/emsesp/EMS-ESP32/issues/2524)
|
||||||
|
- charge optimization [#2543](https://github.com/emsesp/EMS-ESP32/issues/2543)
|
||||||
|
- shower active state retained, shows correctly in HA
|
||||||
|
- MQTT Command Topic with slashes [#2571](https://github.com/emsesp/EMS-ESP32/issues/2571)
|
||||||
|
- Add pulsed water meter input to V1.3 gateway with Lilygo S3 [#2550](https://github.com/emsesp/EMS-ESP32/issues/2550)
|
||||||
|
- fix missing long 10-second press of Button to perform a factory reset
|
||||||
|
- fix wwMaxPower on Junkers ZBS14 [#2609](https://github.com/emsesp/EMS-ESP32/issues/2609)
|
||||||
|
- ventilation bypass state from telegram 0x55C [#1197](https://github.com/emsesp/EMS-ESP32/issues/1197)
|
||||||
|
- set selflowtemp for ems+ boilers [#2641](https://github.com/emsesp/EMS-ESP32/discussions/2641)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- show console log with ISO date/time [#2533](https://github.com/emsesp/EMS-ESP32/discussions/2533)
|
||||||
|
- remove ESP32 CPU temperature
|
||||||
|
- updated core libraries like AsyncTCP, AsyncWebServer and Modbus
|
||||||
|
- remove command `scan deep`
|
||||||
|
- ignore repeated `forceheatingoff` commands [#2641](https://github.com/emsesp/EMS-ESP32/discussions/2641)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ Format: `<type>(<scope>): <subject>`
|
|||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```
|
```text
|
||||||
feat: add hat wobble
|
feat: add hat wobble
|
||||||
^--^ ^------------^
|
^--^ ^------------^
|
||||||
| |
|
| |
|
||||||
@@ -96,7 +96,7 @@ References:
|
|||||||
|
|
||||||
## Contributor License Agreement (CLA)
|
## Contributor License Agreement (CLA)
|
||||||
|
|
||||||
```
|
```text
|
||||||
By making a contribution to this project, I certify that:
|
By making a contribution to this project, I certify that:
|
||||||
|
|
||||||
(a) The contribution was created in whole or in part by me and I
|
(a) The contribution was created in whole or in part by me and I
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -98,13 +98,10 @@ CXX := /usr/bin/g++
|
|||||||
# LDFLAGS Linker Flags
|
# LDFLAGS Linker Flags
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
CPPFLAGS += $(DEFINES) $(DEFAULTS) $(INCLUDE)
|
CPPFLAGS += $(DEFINES) $(DEFAULTS) $(INCLUDE)
|
||||||
CPPFLAGS += -ggdb -g3 -O3
|
CPPFLAGS += -ggdb -g3 -MMD
|
||||||
CPPFLAGS += -MMD
|
|
||||||
CPPFLAGS += -flto=auto -fno-lto
|
CPPFLAGS += -flto=auto -fno-lto
|
||||||
CPPFLAGS += -Wall -Wextra -Werror
|
CPPFLAGS += -Wall -Wextra -Werror -Wswitch-enum
|
||||||
CPPFLAGS += -Wswitch-enum
|
CPPFLAGS += -Wno-unused-parameter -Wno-missing-braces -Wno-vla-cxx-extension
|
||||||
CPPFLAGS += -Wno-unused-parameter
|
|
||||||
CPPFLAGS += -Wno-missing-braces
|
|
||||||
|
|
||||||
CPPFLAGS += $(EXTRA_CPPFLAGS)
|
CPPFLAGS += $(EXTRA_CPPFLAGS)
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
[](https://discord.gg/3J3GgnzpyT)
|
[](https://discord.gg/3J3GgnzpyT)
|
||||||
|
|
||||||
[](https://github.com/emsesp/EMS-ESP32/stargazers)
|
[](https://github.com/emsesp/EMS-ESP32/stargazers)
|
||||||
[](https://github.com/emsesp/EMS-ES32P/network)
|
[](https://github.com/emsesp/EMS-ESP32/network)
|
||||||
[](https://www.paypal.com/paypalme/prderbyshire/2)
|
[](https://www.paypal.com/paypalme/prderbyshire/2)
|
||||||
|
|
||||||
**EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller to communicate with **EMS** (Energy Management System) compatible equipment from manufacturers such as Bosch, Buderus, Nefit, Junkers, Worcester, Sieger, elm.leblanc and iVT.
|
**EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller to communicate with **EMS** (Energy Management System) compatible equipment from manufacturers such as Bosch, Buderus, Nefit, Junkers, Worcester, Sieger, elm.leblanc and iVT.
|
||||||
@@ -60,7 +60,7 @@ It requires a small circuit to interface with the EMS bus which can be purchased
|
|||||||
|
|
||||||
## 🚀 **Installing**
|
## 🚀 **Installing**
|
||||||
|
|
||||||
Head over to [download.emsesp.org](https://download.emsesp.org) for instructions on how to install EMS-ESP. There is also further details on which boards are supported in [this section](https://docs.emsesp.org/Getting-Started/#first-time-install) of the documentation.
|
Head over to [download.emsesp.org](https://download.emsesp.org) for instructions on how to install EMS-ESP. There is also further details on which boards are supported in [this section](https://docs.emsesp.org/Installing/) of the documentation.
|
||||||
|
|
||||||
## 📋 **Documentation**
|
## 📋 **Documentation**
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it
|
|||||||
- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these awesome open source libraries
|
- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these awesome open source libraries
|
||||||
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON processing
|
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON processing
|
||||||
- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client
|
- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client
|
||||||
- ESPAsyncWebServer and AsyncTCP for the Web server and TCP backends, with custom modifications for performance
|
- [ESPAsyncWebServer](https://github.com/ESP32Async/ESPAsyncWebServer) and [AsyncTCP](https://github.com/ESP32Async/AsyncTCP) for the Web server and TCP backends
|
||||||
|
|
||||||
## 📜 **License**
|
## 📜 **License**
|
||||||
|
|
||||||
|
|||||||
48
boards/seeed_xiao_esp32c6.json
Normal file
48
boards/seeed_xiao_esp32c6.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DARDUINO_XIAO_ESP32C6",
|
||||||
|
"-DARDUINO_USB_MODE=1",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "160000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [
|
||||||
|
[
|
||||||
|
"0x2886",
|
||||||
|
"0x0046"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"0x303a",
|
||||||
|
"0x1001"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"mcu": "esp32c6",
|
||||||
|
"variant": "XIAO_ESP32C6"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi",
|
||||||
|
"bluetooth",
|
||||||
|
"zigbee",
|
||||||
|
"thread"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32c6.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "Seeed Studio XIAO ESP32C6",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "4MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 4194304,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"url": "https://wiki.seeedstudio.com/XIAO_ESP32C6_Getting_Started/",
|
||||||
|
"vendor": "Seeed Studio"
|
||||||
|
}
|
||||||
@@ -32,6 +32,8 @@
|
|||||||
"**/*.json",
|
"**/*.json",
|
||||||
"src/core/modbus_entity_parameters.hpp",
|
"src/core/modbus_entity_parameters.hpp",
|
||||||
"sdkconfig.*",
|
"sdkconfig.*",
|
||||||
"managed_components/**"
|
"managed_components/**",
|
||||||
|
"pnpm-*.yaml",
|
||||||
|
"vite.config.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
11214
docs/dump_entities.csv
11214
docs/dump_entities.csv
File diff suppressed because it is too large
Load Diff
@@ -1,227 +0,0 @@
|
|||||||
telegram_type_id,name,is_fetched
|
|
||||||
0x04,UBAFactory,fetched
|
|
||||||
0x06,RCTime,
|
|
||||||
0x0A,EasyMonitor,fetched
|
|
||||||
0x10,UBAErrorMessage1,
|
|
||||||
0x11,UBAErrorMessage2,
|
|
||||||
0x12,RCErrorMessage,
|
|
||||||
0x13,RCErrorMessage2,
|
|
||||||
0x14,UBATotalUptime,fetched
|
|
||||||
0x15,UBAMaintenanceData,
|
|
||||||
0x16,UBAParameters,fetched
|
|
||||||
0x18,UBAMonitorFast,
|
|
||||||
0x19,UBAMonitorSlow,
|
|
||||||
0x1A,UBASetPoints,
|
|
||||||
0x1C,UBAMaintenanceStatus,
|
|
||||||
0x1E,WM10TempMessage,
|
|
||||||
0x23,JunkersSetMixer,fetched
|
|
||||||
0x26,UBASettingsWW,fetched
|
|
||||||
0x28,WeatherComp,fetched
|
|
||||||
0x2A,MC110Status,
|
|
||||||
0x2E,Meters,
|
|
||||||
0x33,UBAParameterWW,fetched
|
|
||||||
0x34,UBAMonitorWW,
|
|
||||||
0x35,UBAFlags,
|
|
||||||
0x37,WWSettings,fetched
|
|
||||||
0x38,WWTimer,fetched
|
|
||||||
0x39,WWCircTimer,fetched
|
|
||||||
0x3A,RC30WWSettings,fetched
|
|
||||||
0x3B,Energy,
|
|
||||||
0x3D,RC35Set,
|
|
||||||
0x3E,RC35Monitor,
|
|
||||||
0x3F,RC35Timer,
|
|
||||||
0x40,RC30Temp,
|
|
||||||
0x41,RC30Monitor,
|
|
||||||
0x42,RC35Timer2,
|
|
||||||
0x47,RC35Set,
|
|
||||||
0x48,RC35Monitor,
|
|
||||||
0x49,RC35Timer,
|
|
||||||
0x4C,RC35Timer2,
|
|
||||||
0x51,RC35Set,
|
|
||||||
0x52,RC35Monitor,
|
|
||||||
0x53,RC35Timer,
|
|
||||||
0x56,RC35Timer2,
|
|
||||||
0x5B,RC35Set,
|
|
||||||
0x5C,RC35Monitor,
|
|
||||||
0x5D,RC35Timer,
|
|
||||||
0x60,RC35Timer2,
|
|
||||||
0x96,SM10Config,fetched
|
|
||||||
0x97,SM10Monitor,
|
|
||||||
0x9C,WM10MonitorMessage,
|
|
||||||
0x9D,WM10SetMessage,
|
|
||||||
0xA2,RCError,
|
|
||||||
0xA3,RCOutdoorTemp,
|
|
||||||
0xA5,IBASettings,fetched
|
|
||||||
0xA7,RC30Set,
|
|
||||||
0xA9,RC30Vacation,fetched
|
|
||||||
0xAA,MMConfigMessage,fetched
|
|
||||||
0xAB,MMStatusMessage,
|
|
||||||
0xAC,MMSetMessage,
|
|
||||||
0xAF,RC20Remote,
|
|
||||||
0xB0,RC10Set,
|
|
||||||
0xB1,RC10Monitor,
|
|
||||||
0xBB,HybridSettings,fetched
|
|
||||||
0xBF,ErrorMessage,
|
|
||||||
0xC2,UBAErrorMessage3,
|
|
||||||
0xD1,UBAOutdoorTemp,
|
|
||||||
0xE3,UBAMonitorSlowPlus2,
|
|
||||||
0xE4,UBAMonitorFastPlus,
|
|
||||||
0xE5,UBAMonitorSlowPlus,
|
|
||||||
0xE6,UBAParametersPlus,fetched
|
|
||||||
0xE9,UBAMonitorWWPlus,
|
|
||||||
0xEA,UBAParameterWWPlus,fetched
|
|
||||||
0x0101,ISM1Set,fetched
|
|
||||||
0x0103,ISM1StatusMessage,fetched
|
|
||||||
0x0104,ISM2StatusMessage,
|
|
||||||
0x010C,IPMStatusMessage,
|
|
||||||
0x011E,IPMTempMessage,
|
|
||||||
0x012E,HPEnergy1,
|
|
||||||
0x013B,HPEnergy2,
|
|
||||||
0x0165,JunkersSet,
|
|
||||||
0x0166,JunkersSet,
|
|
||||||
0x0167,JunkersSet,
|
|
||||||
0x0168,JunkersSet,
|
|
||||||
0x016E,Absent,fetched
|
|
||||||
0x016F,JunkersMonitor,
|
|
||||||
0x0170,JunkersMonitor,
|
|
||||||
0x0171,JunkersMonitor,
|
|
||||||
0x0172,JunkersMonitor,
|
|
||||||
0x0179,JunkersSet,
|
|
||||||
0x017A,JunkersSet,
|
|
||||||
0x017B,JunkersSet,
|
|
||||||
0x017C,JunkersSet,
|
|
||||||
0x01D3,JunkersDhw,fetched
|
|
||||||
0x023A,RC300OutdoorTemp,fetched
|
|
||||||
0x023E,PVSettings,fetched
|
|
||||||
0x0240,RC300Settings,fetched
|
|
||||||
0x0241,RC300Settings,fetched
|
|
||||||
0x0267,RC300Floordry,
|
|
||||||
0x0269,RC300Holiday,fetched
|
|
||||||
0x0291,HPMode,fetched
|
|
||||||
0x0292,HPMode,fetched
|
|
||||||
0x0293,HPMode,fetched
|
|
||||||
0x0294,HPMode,fetched
|
|
||||||
0x029B,RC300Curves,
|
|
||||||
0x029C,RC300Curves,
|
|
||||||
0x029D,RC300Curves,
|
|
||||||
0x029E,RC300Curves,
|
|
||||||
0x029F,RC300Curves,
|
|
||||||
0x02A0,RC300Curves,
|
|
||||||
0x02A1,RC300Curves,
|
|
||||||
0x02A2,RC300Curves,
|
|
||||||
0x02A5,RC300Monitor,fetched
|
|
||||||
0x02A6,RC300Monitor,
|
|
||||||
0x02A7,CRFMonitor,
|
|
||||||
0x02A8,RC300Monitor,
|
|
||||||
0x02A9,RC300Monitor,
|
|
||||||
0x02AA,RC300Monitor,
|
|
||||||
0x02AB,RC300Monitor,
|
|
||||||
0x02AC,RC300Monitor,
|
|
||||||
0x02AF,RC300Summer,
|
|
||||||
0x02B0,RC300Summer,
|
|
||||||
0x02B1,RC300Summer,
|
|
||||||
0x02B2,RC300Summer,
|
|
||||||
0x02B3,RC300Summer,
|
|
||||||
0x02B4,RC300Summer,
|
|
||||||
0x02B5,RC300Summer,
|
|
||||||
0x02B6,RC300Summer,
|
|
||||||
0x02B9,RC300Set,
|
|
||||||
0x02BA,RC300Set,
|
|
||||||
0x02BB,RC300Set,
|
|
||||||
0x02BC,RC300Set,
|
|
||||||
0x02BD,RC300Set,
|
|
||||||
0x02BE,RC300Set,
|
|
||||||
0x02BF,RC300Set,
|
|
||||||
0x02C0,RC300Set,
|
|
||||||
0x02CC,HPPressure,fetched
|
|
||||||
0x02CD,MMPLUSConfigMessage,fetched
|
|
||||||
0x02CE,RC300Set2,
|
|
||||||
0x02D0,RC300Set2,
|
|
||||||
0x02D2,RC300Set2,
|
|
||||||
0x02D6,HPPump2,fetched
|
|
||||||
0x02D7,MMPLUSStatusMessage,
|
|
||||||
0x02F5,RC300WWmode,fetched
|
|
||||||
0x02F6,RC300WW2mode,fetched
|
|
||||||
0x0313,MMPLUSConfigMessage_WWC,fetched
|
|
||||||
0x031B,RC300WWtemp,fetched
|
|
||||||
0x031D,RC300WWmode2,
|
|
||||||
0x031E,RC300WWmode2,
|
|
||||||
0x0331,MMPLUSStatusMessage_WWC,
|
|
||||||
0x0358,SM100SystemConfig,fetched
|
|
||||||
0x035A,SM100CircuitConfig,fetched
|
|
||||||
0x035C,SM100HeatAssist,fetched
|
|
||||||
0x035D,SM100Circuit2Config,fetched
|
|
||||||
0x035F,SM100Config1,fetched
|
|
||||||
0x0361,SM100Differential,fetched
|
|
||||||
0x0362,SM100Monitor,
|
|
||||||
0x0363,SM100Monitor2,
|
|
||||||
0x0364,SM100Status,
|
|
||||||
0x0366,SM100Config,
|
|
||||||
0x036A,SM100Status2,
|
|
||||||
0x0380,SM100CollectorConfig,fetched
|
|
||||||
0x038E,SM100Energy,fetched
|
|
||||||
0x0391,SM100Time,fetched
|
|
||||||
0x043F,CRHolidays,fetched
|
|
||||||
0x0467,HPSet,
|
|
||||||
0x0468,HPSet,
|
|
||||||
0x0469,HPSet,
|
|
||||||
0x046A,HPSet,
|
|
||||||
0x0471,RC300Summer2,
|
|
||||||
0x0472,RC300Summer2,
|
|
||||||
0x0473,RC300Summer2,
|
|
||||||
0x0474,RC300Summer2,
|
|
||||||
0x0475,RC300Summer2,
|
|
||||||
0x0476,RC300Summer2,
|
|
||||||
0x0477,RC300Summer2,
|
|
||||||
0x0478,RC300Summer2,
|
|
||||||
0x047B,HP2,
|
|
||||||
0x0484,HPSilentMode,fetched
|
|
||||||
0x0485,HpCooling,fetched
|
|
||||||
0x0486,HpInConfig,fetched
|
|
||||||
0x0488,HPValve,fetched
|
|
||||||
0x048A,HpPool,fetched
|
|
||||||
0x048B,HPPumps,fetched
|
|
||||||
0x048D,HpPower,fetched
|
|
||||||
0x048F,HpTemperatures,
|
|
||||||
0x0491,HPAdditionalHeater,fetched
|
|
||||||
0x0492,HpHeaterConfig,fetched
|
|
||||||
0x0494,UBAEnergySupplied,
|
|
||||||
0x0495,UBAInformation,
|
|
||||||
0x0499,HPDhwSettings,fetched
|
|
||||||
0x049C,HPSettings2,fetched
|
|
||||||
0x049D,HPSettings3,fetched
|
|
||||||
0x04A2,HpInput,fetched
|
|
||||||
0x04A5,HPFan,fetched
|
|
||||||
0x04A7,HPPowerLimit,fetched
|
|
||||||
0x04AA,HPPower2,fetched
|
|
||||||
0x04AE,HPEnergy,fetched
|
|
||||||
0x04AF,HPMeters,fetched
|
|
||||||
0x056B,VentilationMode,fetched
|
|
||||||
0x0583,VentilationMonitor,
|
|
||||||
0x0585,Blowerspeed,
|
|
||||||
0x0587,Bypass,
|
|
||||||
0x05BA,HpPoolStatus,fetched
|
|
||||||
0x05D9,Airquality,
|
|
||||||
0x0772,HIUSettings,
|
|
||||||
0x0779,HIUMonitor,
|
|
||||||
0x07A5,SM100wwCirc,fetched
|
|
||||||
0x07A6,SM100wwParam,fetched
|
|
||||||
0x07AA,SM100wwStatus,
|
|
||||||
0x07AB,SM100wwCommand,
|
|
||||||
0x07AC,SM100wwParam1,
|
|
||||||
0x07AD,SM100ValveStatus,
|
|
||||||
0x07AE,SM100wwKeepWarm,fetched
|
|
||||||
0x07D6,SM100wwTemperature,
|
|
||||||
0x07E0,SM100wwStatus2,fetched
|
|
||||||
0x0935,EM100SetMessage,fetched
|
|
||||||
0x0936,EM100OutMessage,
|
|
||||||
0x0937,EM100TempMessage,
|
|
||||||
0x0938,EM100InputMessage,
|
|
||||||
0x0939,EM100MonitorMessage,
|
|
||||||
0x093A,EM100ConfigMessage,
|
|
||||||
0x0998,HPSettings,fetched
|
|
||||||
0x0999,HPFunctionTest,fetched
|
|
||||||
0x099A,HPStarts,
|
|
||||||
0x099B,HPFlowTemp,
|
|
||||||
0x099C,HPComp,
|
|
||||||
0x09A0,HPTemperature,
|
|
||||||
|
|||||||
|
4
interface/.gitattributes
vendored
4
interface/.gitattributes
vendored
@@ -1,4 +0,0 @@
|
|||||||
/.yarn/** linguist-vendored
|
|
||||||
/.yarn/releases/* binary
|
|
||||||
/.yarn/plugins/**/* binary
|
|
||||||
/.pnp.* binary linguist-generated
|
|
||||||
@@ -4,5 +4,4 @@ dist/
|
|||||||
src/i18n/*
|
src/i18n/*
|
||||||
|
|
||||||
.prettierrc
|
.prettierrc
|
||||||
.yarn/
|
.typesafe-i18n.json
|
||||||
.typesafe-i18n.json
|
|
||||||
|
|||||||
935
interface/.yarn/releases/yarn-4.7.0.cjs
vendored
935
interface/.yarn/releases/yarn-4.7.0.cjs
vendored
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
|
|||||||
nodeLinker: node-modules
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.7.0.cjs
|
|
||||||
@@ -10,8 +10,7 @@ export default tseslint.config(
|
|||||||
{
|
{
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: true,
|
project: true
|
||||||
tsconfigRootDir: import.meta.dirname
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "EMS-ESP",
|
"name": "EMS-ESP",
|
||||||
"version": "3.7.2",
|
"version": "3.7.3",
|
||||||
"description": "EMS-ESP WebUI",
|
"description": "EMS-ESP WebUI",
|
||||||
"homepage": "https://emsesp.org",
|
"homepage": "https://emsesp.org",
|
||||||
"author": "proddy, emsesp.org",
|
"author": "proddy, emsesp.org",
|
||||||
@@ -8,59 +8,60 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
|
"build-hosted": "typesafe-i18n && vite build --mode hosted",
|
||||||
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"yarn:mock-rest\" \"vite preview\"",
|
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"pnpm:mock-rest\" \"vite preview\"",
|
||||||
"mock-rest": "bun --watch ../mock-api/rest_server.ts",
|
"mock-rest": "bun --watch ../mock-api/restServer.ts",
|
||||||
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"yarn:mock-rest\" \"vite\"",
|
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"pnpm:mock-rest\" \"vite\"",
|
||||||
"typesafe-i18n": "typesafe-i18n --no-watch",
|
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||||
"webUI": "node progmem-generator.js",
|
"webUI": "node progmem-generator.js",
|
||||||
"format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'",
|
"format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'",
|
||||||
"lint": "eslint . --fix"
|
"lint": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alova/adapter-xhr": "2.1.1",
|
"@alova/adapter-xhr": "2.2.1",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/icons-material": "^6.4.8",
|
"@mui/icons-material": "^7.3.4",
|
||||||
"@mui/material": "^6.4.8",
|
"@mui/material": "^7.3.4",
|
||||||
"@table-library/react-table-library": "4.1.12",
|
"@table-library/react-table-library": "4.1.15",
|
||||||
"alova": "3.2.10",
|
"alova": "3.3.4",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
|
"formidable": "^3.5.4",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"mime-types": "^2.1.35",
|
"magic-string": "^0.30.19",
|
||||||
"preact": "^10.26.4",
|
"mime-types": "^3.0.1",
|
||||||
"react": "^19.0.0",
|
"preact": "^10.27.2",
|
||||||
"react-dom": "^19.0.0",
|
"react": "^19.2.0",
|
||||||
|
"react-dom": "^19.2.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-router": "^7.4.0",
|
"react-router": "^7.9.4",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
"typesafe-i18n": "^5.26.2",
|
"typesafe-i18n": "^5.26.2",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.10",
|
"@babel/core": "^7.28.4",
|
||||||
"@eslint/js": "^9.23.0",
|
"@eslint/js": "^9.38.0",
|
||||||
"@preact/compat": "^18.3.1",
|
"@preact/compat": "^18.3.1",
|
||||||
"@preact/preset-vite": "^2.10.1",
|
"@preact/preset-vite": "^2.10.2",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"@types/formidable": "^3",
|
"@types/node": "^24.9.1",
|
||||||
"@types/node": "^22.13.11",
|
"@types/react": "^19.2.2",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react-dom": "^19.2.2",
|
||||||
"@types/react-dom": "^19.0.4",
|
"concurrently": "^9.2.1",
|
||||||
"concurrently": "^9.1.2",
|
"eslint": "^9.38.0",
|
||||||
"eslint": "^9.23.0",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-config-prettier": "^10.1.1",
|
"prettier": "^3.6.2",
|
||||||
"formidable": "^3.5.2",
|
"rollup-plugin-visualizer": "^6.0.5",
|
||||||
"prettier": "^3.5.3",
|
"terser": "^5.44.0",
|
||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"typescript-eslint": "^8.46.2",
|
||||||
"terser": "^5.39.0",
|
"vite": "^7.1.11",
|
||||||
"typescript-eslint": "8.27.0",
|
|
||||||
"vite": "^6.2.2",
|
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"vite-tsconfig-paths": "^5.1.4"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.7.0"
|
"packageManager": "pnpm@10.19.0+sha512.c9fc7236e92adf5c8af42fd5bf1612df99c2ceb62f27047032f4720b33f8eacdde311865e91c411f2774f618d82f320808ecb51718bfa82c060c4ba7c76a32b8"
|
||||||
}
|
}
|
||||||
|
|||||||
6056
interface/pnpm-lock.yaml
generated
Normal file
6056
interface/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
interface/pnpm-workspace.yaml
Normal file
8
interface/pnpm-workspace.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- cwebp-bin
|
||||||
|
- esbuild
|
||||||
|
- gifsicle
|
||||||
|
- jpegtran-bin
|
||||||
|
- mozjpeg
|
||||||
|
- optipng-bin
|
||||||
|
- pngquant-bin
|
||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
existsSync,
|
existsSync,
|
||||||
readFileSync,
|
readFileSync,
|
||||||
readdirSync,
|
readdirSync,
|
||||||
|
statSync,
|
||||||
unlinkSync
|
unlinkSync
|
||||||
} from 'fs';
|
} from 'fs';
|
||||||
import mime from 'mime-types';
|
import mime from 'mime-types';
|
||||||
@@ -15,67 +16,79 @@ const INDENT = ' ';
|
|||||||
const outputPath = '../src/ESP32React/WWWData.h';
|
const outputPath = '../src/ESP32React/WWWData.h';
|
||||||
const sourcePath = './dist';
|
const sourcePath = './dist';
|
||||||
const bytesPerLine = 20;
|
const bytesPerLine = 20;
|
||||||
var totalSize = 0;
|
let totalSize = 0;
|
||||||
|
let bundleStats = {
|
||||||
|
js: { count: 0, uncompressed: 0, compressed: 0 },
|
||||||
|
css: { count: 0, uncompressed: 0, compressed: 0 },
|
||||||
|
html: { count: 0, uncompressed: 0, compressed: 0 },
|
||||||
|
svg: { count: 0, uncompressed: 0, compressed: 0 },
|
||||||
|
other: { count: 0, uncompressed: 0, compressed: 0 }
|
||||||
|
};
|
||||||
|
|
||||||
const generateWWWClass = () =>
|
const generateWWWClass =
|
||||||
`typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
|
() => `typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
|
||||||
// Total size is ${totalSize} bytes
|
// Bundle Statistics:
|
||||||
|
// - Total compressed size: ${(totalSize / 1000).toFixed(1)} KB
|
||||||
|
// - Total uncompressed size: ${(Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0) / 1000).toFixed(1)} KB
|
||||||
|
// - Compression ratio: ${(((Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0) - totalSize) / Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0)) * 100).toFixed(1)}%
|
||||||
|
// - Generated on: ${new Date().toISOString()}
|
||||||
|
|
||||||
class WWWData {
|
class WWWData {
|
||||||
${indent}public:
|
${INDENT}public:
|
||||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
${INDENT.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||||
${fileInfo.map((file) => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size}, "${file.hash}");`).join('\n')}
|
${fileInfo.map((f) => `${INDENT.repeat(3)}handler("${f.uri}", "${f.mimeType}", ${f.variable}, ${f.size}, "${f.hash}");`).join('\n')}
|
||||||
${indent.repeat(2)}}
|
${INDENT.repeat(2)}}
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function getFilesSync(dir, files = []) {
|
const getFilesSync = (dir, files = []) => {
|
||||||
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||||
const entryPath = resolve(dir, entry.name);
|
const entryPath = resolve(dir, entry.name);
|
||||||
if (entry.isDirectory()) {
|
entry.isDirectory() ? getFilesSync(entryPath, files) : files.push(entryPath);
|
||||||
getFilesSync(entryPath, files);
|
|
||||||
} else {
|
|
||||||
files.push(entryPath);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return files;
|
return files;
|
||||||
}
|
};
|
||||||
|
|
||||||
function cleanAndOpen(path) {
|
const cleanAndOpen = (path) => {
|
||||||
if (existsSync(path)) {
|
existsSync(path) && unlinkSync(path);
|
||||||
unlinkSync(path);
|
|
||||||
}
|
|
||||||
return createWriteStream(path, { flags: 'w+' });
|
return createWriteStream(path, { flags: 'w+' });
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const getFileType = (filePath) => {
|
||||||
|
const ext = filePath.split('.').pop().toLowerCase();
|
||||||
|
if (ext === 'js') return 'js';
|
||||||
|
if (ext === 'css') return 'css';
|
||||||
|
if (ext === 'html') return 'html';
|
||||||
|
if (ext === 'svg') return 'svg';
|
||||||
|
return 'other';
|
||||||
|
};
|
||||||
|
|
||||||
const writeFile = (relativeFilePath, buffer) => {
|
const writeFile = (relativeFilePath, buffer) => {
|
||||||
const variable = 'ESP_REACT_DATA_' + fileInfo.length;
|
const variable = `ESP_REACT_DATA_${fileInfo.length}`;
|
||||||
const mimeType = mime.lookup(relativeFilePath);
|
const mimeType = mime.lookup(relativeFilePath);
|
||||||
var size = 0;
|
const fileType = getFileType(relativeFilePath);
|
||||||
writeStream.write('const uint8_t ' + variable + '[] = {');
|
let size = 0;
|
||||||
// const zipBuffer = zlib.brotliCompressSync(buffer, { quality: 1 });
|
writeStream.write(`const uint8_t ${variable}[] = {`);
|
||||||
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
|
||||||
|
|
||||||
// create sha
|
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
||||||
const hashSum = crypto.createHash('sha256');
|
const hash = crypto.createHash('sha256').update(zipBuffer).digest('hex');
|
||||||
hashSum.update(zipBuffer);
|
|
||||||
const hash = hashSum.digest('hex');
|
|
||||||
|
|
||||||
zipBuffer.forEach((b) => {
|
zipBuffer.forEach((b) => {
|
||||||
if (!(size % bytesPerLine)) {
|
if (!(size % bytesPerLine)) {
|
||||||
writeStream.write('\n');
|
writeStream.write('\n' + INDENT);
|
||||||
writeStream.write(indent);
|
|
||||||
}
|
}
|
||||||
writeStream.write('0x' + ('00' + b.toString(16).toUpperCase()).slice(-2) + ',');
|
writeStream.write('0x' + b.toString(16).toUpperCase().padStart(2, '0') + ',');
|
||||||
size++;
|
size++;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (size % bytesPerLine) {
|
size % bytesPerLine && writeStream.write('\n');
|
||||||
writeStream.write('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
writeStream.write('};\n\n');
|
writeStream.write('};\n\n');
|
||||||
|
|
||||||
|
// Update bundle statistics
|
||||||
|
bundleStats[fileType].count++;
|
||||||
|
bundleStats[fileType].uncompressed += buffer.length;
|
||||||
|
bundleStats[fileType].compressed += zipBuffer.length;
|
||||||
|
|
||||||
fileInfo.push({
|
fileInfo.push({
|
||||||
uri: '/' + relativeFilePath.replace(sep, '/'),
|
uri: '/' + relativeFilePath.replace(sep, '/'),
|
||||||
mimeType,
|
mimeType,
|
||||||
@@ -84,32 +97,52 @@ const writeFile = (relativeFilePath, buffer) => {
|
|||||||
hash
|
hash
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log(relativeFilePath + ' (size ' + size + ' bytes)');
|
|
||||||
totalSize += size;
|
totalSize += size;
|
||||||
};
|
};
|
||||||
|
|
||||||
// start
|
console.log(`Generating ${outputPath} from ${sourcePath}`);
|
||||||
console.log('Generating ' + outputPath + ' from ' + sourcePath);
|
|
||||||
const includes = ARDUINO_INCLUDES;
|
|
||||||
const indent = INDENT;
|
|
||||||
const fileInfo = [];
|
const fileInfo = [];
|
||||||
const writeStream = cleanAndOpen(resolve(outputPath));
|
const writeStream = cleanAndOpen(resolve(outputPath));
|
||||||
|
|
||||||
// includes
|
writeStream.write(ARDUINO_INCLUDES);
|
||||||
writeStream.write(includes);
|
|
||||||
|
|
||||||
// process static files
|
|
||||||
const buildPath = resolve(sourcePath);
|
const buildPath = resolve(sourcePath);
|
||||||
for (const filePath of getFilesSync(buildPath)) {
|
for (const filePath of getFilesSync(buildPath)) {
|
||||||
const readStream = readFileSync(filePath);
|
writeFile(relative(buildPath, filePath), readFileSync(filePath));
|
||||||
const relativeFilePath = relative(buildPath, filePath);
|
|
||||||
writeFile(relativeFilePath, readStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add class
|
|
||||||
writeStream.write(generateWWWClass());
|
writeStream.write(generateWWWClass());
|
||||||
|
|
||||||
// end
|
|
||||||
writeStream.end();
|
writeStream.end();
|
||||||
|
|
||||||
console.log('Total size: ' + totalSize / 1000 + ' KB');
|
// Calculate and display bundle statistics
|
||||||
|
const totalUncompressed = Object.values(bundleStats).reduce(
|
||||||
|
(sum, stat) => sum + stat.uncompressed,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const totalCompressed = Object.values(bundleStats).reduce(
|
||||||
|
(sum, stat) => sum + stat.compressed,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const compressionRatio = (
|
||||||
|
((totalUncompressed - totalCompressed) / totalUncompressed) *
|
||||||
|
100
|
||||||
|
).toFixed(1);
|
||||||
|
|
||||||
|
console.log('\n📊 Bundle Size Analysis:');
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
console.log(`Total compressed size: ${(totalSize / 1000).toFixed(1)} KB`);
|
||||||
|
console.log(`Total uncompressed size: ${(totalUncompressed / 1000).toFixed(1)} KB`);
|
||||||
|
console.log(`Compression ratio: ${compressionRatio}%`);
|
||||||
|
console.log('\n📁 File Type Breakdown:');
|
||||||
|
Object.entries(bundleStats).forEach(([type, stats]) => {
|
||||||
|
if (stats.count > 0) {
|
||||||
|
const ratio = (
|
||||||
|
((stats.uncompressed - stats.compressed) / stats.uncompressed) *
|
||||||
|
100
|
||||||
|
).toFixed(1);
|
||||||
|
console.log(
|
||||||
|
`${type.toUpperCase().padEnd(4)}: ${stats.count} files, ${(stats.uncompressed / 1000).toFixed(1)} KB → ${(stats.compressed / 1000).toFixed(1)} KB (${ratio}% compression)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
|||||||
@@ -37,10 +37,9 @@ const AuthenticatedRouting = () => {
|
|||||||
<Route path="/dashboard/*" element={<Dashboard />} />
|
<Route path="/dashboard/*" element={<Dashboard />} />
|
||||||
<Route path="/devices/*" element={<Devices />} />
|
<Route path="/devices/*" element={<Devices />} />
|
||||||
<Route path="/sensors/*" element={<Sensors />} />
|
<Route path="/sensors/*" element={<Sensors />} />
|
||||||
<Route path="/status/*" element={<Status />} />
|
|
||||||
<Route path="/help/*" element={<Help />} />
|
<Route path="/help/*" element={<Help />} />
|
||||||
<Route path="/*" element={<Navigate to="/" />} />
|
|
||||||
|
|
||||||
|
<Route path="/status/*" element={<Status />} />
|
||||||
<Route path="/status/hardwarestatus/*" element={<HardwareStatus />} />
|
<Route path="/status/hardwarestatus/*" element={<HardwareStatus />} />
|
||||||
<Route path="/status/activity" element={<Activity />} />
|
<Route path="/status/activity" element={<Activity />} />
|
||||||
<Route path="/status/log" element={<SystemLog />} />
|
<Route path="/status/log" element={<SystemLog />} />
|
||||||
@@ -68,6 +67,8 @@ const AuthenticatedRouting = () => {
|
|||||||
<Route path="/customentities" element={<CustomEntities />} />
|
<Route path="/customentities" element={<CustomEntities />} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Route path="/*" element={<Navigate to="/" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const SignIn = () => {
|
|||||||
|
|
||||||
<Box display="flex" flexDirection="column" alignItems="center">
|
<Box display="flex" flexDirection="column" alignItems="center">
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
disabled={processing}
|
disabled={processing}
|
||||||
sx={{
|
sx={{
|
||||||
width: 240
|
width: 240
|
||||||
@@ -117,7 +117,7 @@ const SignIn = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
disabled={processing}
|
disabled={processing}
|
||||||
sx={{
|
sx={{
|
||||||
width: 240
|
width: 240
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export const readDeviceEntities = (id: number) =>
|
|||||||
alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
|
alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
|
||||||
params: { id },
|
params: { id },
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
|
// @ts-expect-error - exactOptionalPropertyTypes compatibility issue
|
||||||
transform(data) {
|
transform(data) {
|
||||||
return (data as DeviceEntity[]).map((de: DeviceEntity) => ({
|
return (data as DeviceEntity[]).map((de: DeviceEntity) => ({
|
||||||
...de,
|
...de,
|
||||||
@@ -92,6 +93,7 @@ export const writeDeviceName = (data: { id: number; name: string }) =>
|
|||||||
// SettingsScheduler
|
// SettingsScheduler
|
||||||
export const readSchedule = () =>
|
export const readSchedule = () =>
|
||||||
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
|
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
|
||||||
|
// @ts-expect-error - exactOptionalPropertyTypes compatibility issue
|
||||||
transform(data) {
|
transform(data) {
|
||||||
return (data as Schedule).schedule.map((si: ScheduleItem) => ({
|
return (data as Schedule).schedule.map((si: ScheduleItem) => ({
|
||||||
...si,
|
...si,
|
||||||
@@ -129,6 +131,7 @@ export const writeModules = (data: {
|
|||||||
// CustomEntities
|
// CustomEntities
|
||||||
export const readCustomEntities = () =>
|
export const readCustomEntities = () =>
|
||||||
alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
|
alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
|
||||||
|
// @ts-expect-error - exactOptionalPropertyTypes compatibility issue
|
||||||
transform(data) {
|
transform(data) {
|
||||||
return (data as Entities).entities.map((ei: EntityItem) => ({
|
return (data as Entities).entities.map((ei: EntityItem) => ({
|
||||||
...ei,
|
...ei,
|
||||||
@@ -143,7 +146,8 @@ export const readCustomEntities = () =>
|
|||||||
o_name: ei.name,
|
o_name: ei.name,
|
||||||
o_writeable: ei.writeable,
|
o_writeable: ei.writeable,
|
||||||
o_value: ei.value,
|
o_value: ei.value,
|
||||||
o_deleted: ei.deleted
|
o_deleted: ei.deleted,
|
||||||
|
o_hide: ei.hide
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const getDevVersion = () =>
|
|||||||
cacheFor: 60 * 10 * 1000,
|
cacheFor: 60 * 10 * 1000,
|
||||||
transform(response: { data: { name: string; published_at: string } }) {
|
transform(response: { data: { name: string; published_at: string } }) {
|
||||||
return {
|
return {
|
||||||
name: response.data.name.split(/\s+/).splice(-1)[0].substring(1),
|
name: response.data.name.split(/\s+/).splice(-1)[0]?.substring(1) || '',
|
||||||
published_at: response.data.published_at
|
published_at: response.data.published_at
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,37 @@
|
|||||||
let decoder;
|
// @ts-nocheck - Optimized MessagePack unpacking library for EMS-ESP32
|
||||||
|
let decoder,
|
||||||
|
src,
|
||||||
|
srcEnd,
|
||||||
|
position = 0,
|
||||||
|
strings = [],
|
||||||
|
stringPosition = 0,
|
||||||
|
currentUnpackr = {},
|
||||||
|
currentStructures,
|
||||||
|
srcString,
|
||||||
|
srcStringStart = 0,
|
||||||
|
srcStringEnd = 0,
|
||||||
|
bundledStrings,
|
||||||
|
referenceMap,
|
||||||
|
dataView;
|
||||||
|
const EMPTY_ARRAY = [],
|
||||||
|
currentExtensions = [];
|
||||||
|
const defaultOptions = { useRecords: false, mapsAsObjects: true };
|
||||||
try {
|
try {
|
||||||
decoder = new TextDecoder();
|
decoder = new TextDecoder();
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
let src;
|
class C1Type {}
|
||||||
let srcEnd;
|
const C1 = new C1Type();
|
||||||
let position = 0;
|
|
||||||
const EMPTY_ARRAY = [];
|
|
||||||
let strings = EMPTY_ARRAY;
|
|
||||||
let stringPosition = 0;
|
|
||||||
let currentUnpackr = {};
|
|
||||||
let currentStructures;
|
|
||||||
let srcString;
|
|
||||||
let srcStringStart = 0;
|
|
||||||
let srcStringEnd = 0;
|
|
||||||
let bundledStrings;
|
|
||||||
let referenceMap;
|
|
||||||
const currentExtensions = [];
|
|
||||||
let dataView;
|
|
||||||
const defaultOptions = {
|
|
||||||
useRecords: false,
|
|
||||||
mapsAsObjects: true
|
|
||||||
};
|
|
||||||
export class C1Type {}
|
|
||||||
export const C1 = new C1Type();
|
|
||||||
C1.name = 'MessagePack 0xC1';
|
C1.name = 'MessagePack 0xC1';
|
||||||
let sequentialMode = false;
|
let sequentialMode = false,
|
||||||
let inlineObjectReadThreshold = 2;
|
inlineObjectReadThreshold = 2,
|
||||||
let readStruct, onLoadedStructures, onSaveState;
|
readStruct,
|
||||||
// no-eval build
|
onLoadedStructures,
|
||||||
|
onSaveState;
|
||||||
try {
|
try {
|
||||||
new Function('');
|
new Function('');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// if eval variants are not supported, do not create inline object readers ever
|
|
||||||
inlineObjectReadThreshold = Infinity;
|
inlineObjectReadThreshold = Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Unpackr {
|
export class Unpackr {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
if (options) {
|
if (options) {
|
||||||
@@ -50,19 +47,15 @@ export class Unpackr {
|
|||||||
if (options.structures)
|
if (options.structures)
|
||||||
options.structures.sharedLength = options.structures.length;
|
options.structures.sharedLength = options.structures.length;
|
||||||
else if (options.getStructures) {
|
else if (options.getStructures) {
|
||||||
(options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures
|
(options.structures = []).uninitialized = true;
|
||||||
options.structures.sharedLength = 0;
|
options.structures.sharedLength = 0;
|
||||||
}
|
}
|
||||||
if (options.int64AsNumber) {
|
if (options.int64AsNumber) options.int64AsType = 'number';
|
||||||
options.int64AsType = 'number';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Object.assign(this, options);
|
Object.assign(this, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack(source, options?: any) {
|
unpack(source, options?: any) {
|
||||||
if (src) {
|
if (src) {
|
||||||
// re-entrant execution, save the state and restore it after we do this unpack
|
|
||||||
return saveState(() => {
|
return saveState(() => {
|
||||||
clearSource();
|
clearSource();
|
||||||
return this
|
return this
|
||||||
@@ -86,9 +79,6 @@ export class Unpackr {
|
|||||||
strings = EMPTY_ARRAY;
|
strings = EMPTY_ARRAY;
|
||||||
bundledStrings = null;
|
bundledStrings = null;
|
||||||
src = source;
|
src = source;
|
||||||
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
||||||
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
||||||
// new ones
|
|
||||||
try {
|
try {
|
||||||
dataView =
|
dataView =
|
||||||
source.dataView ||
|
source.dataView ||
|
||||||
@@ -191,10 +181,10 @@ export class Unpackr {
|
|||||||
return this.unpack(source, end);
|
return this.unpack(source, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function getPosition() {
|
function getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
export function checkedRead(options: any) {
|
function checkedRead(options: any) {
|
||||||
try {
|
try {
|
||||||
if (!currentUnpackr.trusted && !sequentialMode) {
|
if (!currentUnpackr.trusted && !sequentialMode) {
|
||||||
const sharedLength = currentStructures.sharedLength || 0;
|
const sharedLength = currentStructures.sharedLength || 0;
|
||||||
@@ -264,7 +254,7 @@ function restoreStructures() {
|
|||||||
currentStructures.restoreStructures = null;
|
currentStructures.restoreStructures = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function read() {
|
function read() {
|
||||||
let token = src[position++];
|
let token = src[position++];
|
||||||
if (token < 0xa0) {
|
if (token < 0xa0) {
|
||||||
if (token < 0x80) {
|
if (token < 0x80) {
|
||||||
@@ -589,7 +579,7 @@ const createSecondByteReader = (firstId, read0) =>
|
|||||||
return structure.read();
|
return structure.read();
|
||||||
};
|
};
|
||||||
|
|
||||||
export function loadStructures() {
|
function loadStructures() {
|
||||||
const loadedStructures = saveState(() => {
|
const loadedStructures = saveState(() => {
|
||||||
// save the state in case getStructures modifies our buffer
|
// save the state in case getStructures modifies our buffer
|
||||||
src = null;
|
src = null;
|
||||||
@@ -605,9 +595,8 @@ var readFixedString = readStringJS;
|
|||||||
var readString8 = readStringJS;
|
var readString8 = readStringJS;
|
||||||
var readString16 = readStringJS;
|
var readString16 = readStringJS;
|
||||||
var readString32 = readStringJS;
|
var readString32 = readStringJS;
|
||||||
export let isNativeAccelerationEnabled = false;
|
let isNativeAccelerationEnabled = false;
|
||||||
|
function setExtractor(extractStrings) {
|
||||||
export function setExtractor(extractStrings) {
|
|
||||||
isNativeAccelerationEnabled = true;
|
isNativeAccelerationEnabled = true;
|
||||||
readFixedString = readString(1);
|
readFixedString = readString(1);
|
||||||
readString8 = readString(2);
|
readString8 = readString(2);
|
||||||
@@ -701,7 +690,7 @@ function readStringJS(length) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
export function readString(source, start, length) {
|
function readString(source, start, length) {
|
||||||
const existingSrc = src;
|
const existingSrc = src;
|
||||||
src = source;
|
src = source;
|
||||||
position = start;
|
position = start;
|
||||||
@@ -1065,7 +1054,7 @@ currentExtensions[0x70] = (data) => {
|
|||||||
|
|
||||||
currentExtensions[0x73] = () => new Set(read());
|
currentExtensions[0x73] = () => new Set(read());
|
||||||
|
|
||||||
export const typedArrays = [
|
const typedArrays = [
|
||||||
'Int8',
|
'Int8',
|
||||||
'Uint8',
|
'Uint8',
|
||||||
'Uint8Clamped',
|
'Uint8Clamped',
|
||||||
@@ -1177,44 +1166,20 @@ function saveState(callback) {
|
|||||||
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
export function clearSource() {
|
function clearSource() {
|
||||||
src = null;
|
src = null;
|
||||||
referenceMap = null;
|
referenceMap = null;
|
||||||
currentStructures = null;
|
currentStructures = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addExtension(extension) {
|
function addExtension(extension) {
|
||||||
if (extension.unpack) currentExtensions[extension.type] = extension.unpack;
|
if (extension.unpack) currentExtensions[extension.type] = extension.unpack;
|
||||||
else currentExtensions[extension.type] = extension;
|
else currentExtensions[extension.type] = extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
const mult10 = new Array(147);
|
||||||
for (let i = 0; i < 256; i++) {
|
for (let i = 0; i < 256; i++) {
|
||||||
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
|
||||||
}
|
}
|
||||||
export const Decoder = Unpackr;
|
const defaultUnpackr = new Unpackr({ useRecords: false });
|
||||||
var defaultUnpackr = new Unpackr({ useRecords: false });
|
|
||||||
export const unpack = defaultUnpackr.unpack;
|
export const unpack = defaultUnpackr.unpack;
|
||||||
export const unpackMultiple = defaultUnpackr.unpackMultiple;
|
|
||||||
export const decode = defaultUnpackr.unpack;
|
|
||||||
export const FLOAT32_OPTIONS = {
|
|
||||||
NEVER: 0,
|
|
||||||
ALWAYS: 1,
|
|
||||||
DECIMAL_ROUND: 3,
|
|
||||||
DECIMAL_FIT: 4
|
|
||||||
};
|
|
||||||
const f32Array = new Float32Array(1);
|
|
||||||
const u8Array = new Uint8Array(f32Array.buffer, 0, 4);
|
|
||||||
export function roundFloat32(float32Number) {
|
|
||||||
f32Array[0] = float32Number;
|
|
||||||
const multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
|
|
||||||
return (
|
|
||||||
((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) /
|
|
||||||
multiplier
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function setReadStruct(updatedReadStruct, loadedStructs, saveState) {
|
|
||||||
readStruct = updatedReadStruct;
|
|
||||||
onLoadedStructures = loadedStructs;
|
|
||||||
onSaveState = saveState;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ const CustomEntities = () => {
|
|||||||
ei.factor !== ei.o_factor ||
|
ei.factor !== ei.o_factor ||
|
||||||
ei.value_type !== ei.o_value_type ||
|
ei.value_type !== ei.o_value_type ||
|
||||||
ei.writeable !== ei.o_writeable ||
|
ei.writeable !== ei.o_writeable ||
|
||||||
|
ei.hide !== ei.o_hide ||
|
||||||
ei.deleted !== ei.o_deleted ||
|
ei.deleted !== ei.o_deleted ||
|
||||||
(ei.value || '') !== (ei.o_value || '')
|
(ei.value || '') !== (ei.o_value || '')
|
||||||
);
|
);
|
||||||
@@ -136,8 +137,8 @@ const CustomEntities = () => {
|
|||||||
const saveEntities = async () => {
|
const saveEntities = async () => {
|
||||||
await writeEntities({
|
await writeEntities({
|
||||||
entities: entities
|
entities: entities
|
||||||
.filter((ei) => !ei.deleted)
|
.filter((ei: EntityItem) => !ei.deleted)
|
||||||
.map((condensed_ei) => ({
|
.map((condensed_ei: EntityItem) => ({
|
||||||
id: condensed_ei.id,
|
id: condensed_ei.id,
|
||||||
ram: condensed_ei.ram,
|
ram: condensed_ei.ram,
|
||||||
name: condensed_ei.name,
|
name: condensed_ei.name,
|
||||||
@@ -147,6 +148,7 @@ const CustomEntities = () => {
|
|||||||
factor: condensed_ei.factor,
|
factor: condensed_ei.factor,
|
||||||
uom: condensed_ei.uom,
|
uom: condensed_ei.uom,
|
||||||
writeable: condensed_ei.writeable,
|
writeable: condensed_ei.writeable,
|
||||||
|
hide: condensed_ei.hide,
|
||||||
value_type: condensed_ei.value_type,
|
value_type: condensed_ei.value_type,
|
||||||
value: condensed_ei.value
|
value: condensed_ei.value
|
||||||
}))
|
}))
|
||||||
@@ -209,6 +211,7 @@ const CustomEntities = () => {
|
|||||||
value_type: item.value_type,
|
value_type: item.value_type,
|
||||||
writeable: item.writeable,
|
writeable: item.writeable,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
|
hide: item.hide,
|
||||||
value: item.value
|
value: item.value
|
||||||
});
|
});
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
@@ -228,6 +231,7 @@ const CustomEntities = () => {
|
|||||||
value_type: 0,
|
value_type: 0,
|
||||||
writeable: false,
|
writeable: false,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
|
hide: false,
|
||||||
value: ''
|
value: ''
|
||||||
});
|
});
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
@@ -248,15 +252,17 @@ const CustomEntities = () => {
|
|||||||
|
|
||||||
const renderEntity = () => {
|
const renderEntity = () => {
|
||||||
if (!entities) {
|
if (!entities) {
|
||||||
return <FormLoader onRetry={fetchEntities} errorMessage={error?.message} />;
|
return (
|
||||||
|
<FormLoader onRetry={fetchEntities} errorMessage={error?.message || ''} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
data={{
|
data={{
|
||||||
nodes: entities
|
nodes: entities
|
||||||
.filter((ei) => !ei.deleted)
|
.filter((ei: EntityItem) => !ei.deleted)
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a: EntityItem, b: EntityItem) => a.name.localeCompare(b.name))
|
||||||
}}
|
}}
|
||||||
theme={entity_theme}
|
theme={entity_theme}
|
||||||
layout={{ custom: true }}
|
layout={{ custom: true }}
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { useEffect, useState } from 'react';
|
|||||||
|
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
|
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||||
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
|
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
||||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@@ -12,7 +16,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField
|
TextField
|
||||||
@@ -70,7 +74,10 @@ const CustomEntitiesDialog = ({
|
|||||||
}
|
}
|
||||||
}, [open, selectedItem]);
|
}, [open, selectedItem]);
|
||||||
|
|
||||||
const handleClose = (_event, reason: 'backdropClick' | 'escapeKeyDown') => {
|
const handleClose = (
|
||||||
|
_event: React.SyntheticEvent,
|
||||||
|
reason: 'backdropClick' | 'escapeKeyDown'
|
||||||
|
) => {
|
||||||
if (reason !== 'backdropClick') {
|
if (reason !== 'backdropClick') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -119,7 +126,7 @@ const CustomEntitiesDialog = ({
|
|||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid size={12}>
|
<Grid size={12}>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="name"
|
name="name"
|
||||||
label={LL.NAME(0)}
|
label={LL.NAME(0)}
|
||||||
value={editItem.name}
|
value={editItem.name}
|
||||||
@@ -128,6 +135,20 @@ const CustomEntitiesDialog = ({
|
|||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid mt={3}>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
icon={<InsertCommentOutlinedIcon htmlColor="white" />}
|
||||||
|
checkedIcon={<CommentsDisabledOutlinedIcon color="primary" />}
|
||||||
|
checked={editItem.hide}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="hide"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="API/MQTT"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="ram"
|
name="ram"
|
||||||
@@ -177,10 +198,12 @@ const CustomEntitiesDialog = ({
|
|||||||
)}
|
)}
|
||||||
{editItem.ram === 0 && (
|
{editItem.ram === 0 && (
|
||||||
<>
|
<>
|
||||||
<Grid mt={3} size={9}>
|
<Grid mt={3}>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
icon={<EditOffOutlinedIcon color="primary" />}
|
||||||
|
checkedIcon={<EditOutlinedIcon htmlColor="white" />}
|
||||||
checked={editItem.writeable}
|
checked={editItem.writeable}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
name="writeable"
|
name="writeable"
|
||||||
@@ -191,7 +214,7 @@ const CustomEntitiesDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="device_id"
|
name="device_id"
|
||||||
label={LL.ID_OF(LL.DEVICE())}
|
label={LL.ID_OF(LL.DEVICE())}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
@@ -211,7 +234,7 @@ const CustomEntitiesDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="type_id"
|
name="type_id"
|
||||||
label={LL.ID_OF(LL.TYPE(1))}
|
label={LL.ID_OF(LL.TYPE(1))}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
@@ -231,7 +254,7 @@ const CustomEntitiesDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="offset"
|
name="offset"
|
||||||
label={LL.OFFSET()}
|
label={LL.OFFSET()}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
@@ -323,7 +346,7 @@ const CustomEntitiesDialog = ({
|
|||||||
editItem.device_id !== '0' && (
|
editItem.device_id !== '0' && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="factor"
|
name="factor"
|
||||||
label={LL.BYTES()}
|
label={LL.BYTES()}
|
||||||
value={numberValue(editItem.factor as number)}
|
value={numberValue(editItem.factor as number)}
|
||||||
@@ -341,7 +364,7 @@ const CustomEntitiesDialog = ({
|
|||||||
{editItem.value_type === DeviceValueType.BOOL && (
|
{editItem.value_type === DeviceValueType.BOOL && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="factor"
|
name="factor"
|
||||||
label={LL.BITMASK()}
|
label={LL.BITMASK()}
|
||||||
value={editItem.factor as string}
|
value={editItem.factor as string}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
Link,
|
Link,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
@@ -125,13 +125,22 @@ const Customizations = () => {
|
|||||||
|
|
||||||
const setOriginalSettings = (data: DeviceEntity[]) => {
|
const setOriginalSettings = (data: DeviceEntity[]) => {
|
||||||
setDeviceEntities(
|
setDeviceEntities(
|
||||||
data.map((de) => ({
|
data.map((de) => {
|
||||||
...de,
|
const result: DeviceEntity = {
|
||||||
o_m: de.m,
|
...de,
|
||||||
o_cn: de.cn,
|
o_m: de.m
|
||||||
o_mi: de.mi,
|
};
|
||||||
o_ma: de.ma
|
if (de.cn !== undefined) {
|
||||||
}))
|
result.o_cn = de.cn;
|
||||||
|
}
|
||||||
|
if (de.mi !== undefined) {
|
||||||
|
result.o_mi = de.mi;
|
||||||
|
}
|
||||||
|
if (de.ma !== undefined) {
|
||||||
|
result.o_ma = de.ma;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -244,8 +253,11 @@ const Customizations = () => {
|
|||||||
setSelectedDevice(-1);
|
setSelectedDevice(-1);
|
||||||
setSelectedDeviceTypeNameURL('');
|
setSelectedDeviceTypeNameURL('');
|
||||||
} else {
|
} else {
|
||||||
setSelectedDeviceTypeNameURL(devices.devices[index].url || '');
|
const device = devices.devices[index];
|
||||||
setSelectedDeviceName(devices.devices[index].n);
|
if (device) {
|
||||||
|
setSelectedDeviceTypeNameURL(device.url || '');
|
||||||
|
setSelectedDeviceName(device.n);
|
||||||
|
}
|
||||||
setNumChanges(0);
|
setNumChanges(0);
|
||||||
setRestartNeeded(false);
|
setRestartNeeded(false);
|
||||||
}
|
}
|
||||||
@@ -306,7 +318,7 @@ const Customizations = () => {
|
|||||||
|
|
||||||
const filter_entity = (de: DeviceEntity) =>
|
const filter_entity = (de: DeviceEntity) =>
|
||||||
(de.m & selectedFilters || !selectedFilters) &&
|
(de.m & selectedFilters || !selectedFilters) &&
|
||||||
formatName(de, true).includes(search);
|
formatName(de, true).toLowerCase().includes(search.toLowerCase());
|
||||||
|
|
||||||
const maskDisabled = (set: boolean) => {
|
const maskDisabled = (set: boolean) => {
|
||||||
setDeviceEntities(
|
setDeviceEntities(
|
||||||
@@ -396,14 +408,20 @@ const Customizations = () => {
|
|||||||
await sendCustomizationEntities({
|
await sendCustomizationEntities({
|
||||||
id: selectedDevice,
|
id: selectedDevice,
|
||||||
entity_ids: masked_entities
|
entity_ids: masked_entities
|
||||||
}).catch((error: Error) => {
|
})
|
||||||
if (error.message === 'Reboot required') {
|
.then(() => {
|
||||||
setRestartNeeded(true);
|
toast.success(LL.CUSTOMIZATIONS_SAVED());
|
||||||
} else {
|
})
|
||||||
toast.error(error.message);
|
.catch((error: Error) => {
|
||||||
}
|
if (error.message === 'Reboot required') {
|
||||||
});
|
setRestartNeeded(true);
|
||||||
setOriginalSettings(deviceEntities);
|
} else {
|
||||||
|
toast.error(error.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setOriginalSettings(deviceEntities);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -545,7 +563,7 @@ const Customizations = () => {
|
|||||||
size="small"
|
size="small"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
value={getMaskString(selectedFilters)}
|
value={getMaskString(selectedFilters)}
|
||||||
onChange={(event, mask: string[]) => {
|
onChange={(_, mask: string[]) => {
|
||||||
setSelectedFilters(getMaskNumber(mask));
|
setSelectedFilters(getMaskNumber(mask));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
TextField,
|
TextField,
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
@@ -54,7 +54,10 @@ const CustomizationsDialog = ({
|
|||||||
}
|
}
|
||||||
}, [open, selectedItem]);
|
}, [open, selectedItem]);
|
||||||
|
|
||||||
const handleClose = (_event, reason: 'backdropClick' | 'escapeKeyDown') => {
|
const handleClose = (
|
||||||
|
_event: React.SyntheticEvent,
|
||||||
|
reason: 'backdropClick' | 'escapeKeyDown'
|
||||||
|
) => {
|
||||||
if (reason !== 'backdropClick') {
|
if (reason !== 'backdropClick') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useContext, useEffect, useState } from 'react';
|
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { IconContext } from 'react-icons/lib';
|
import { IconContext } from 'react-icons/lib';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
@@ -76,35 +76,40 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
const deviceValueDialogSave = useCallback(
|
||||||
if (!selectedDashboardItem) {
|
async (devicevalue: DeviceValue) => {
|
||||||
return;
|
if (!selectedDashboardItem) {
|
||||||
}
|
return;
|
||||||
const id = selectedDashboardItem.parentNode.id; // this is the parent ID
|
}
|
||||||
await sendDeviceValue({ id, c: devicevalue.c ?? '', v: devicevalue.v })
|
const id = selectedDashboardItem.id; // this is the parent ID
|
||||||
.then(() => {
|
await sendDeviceValue({ id, c: devicevalue.c ?? '', v: devicevalue.v })
|
||||||
toast.success(LL.WRITE_CMD_SENT());
|
.then(() => {
|
||||||
})
|
toast.success(LL.WRITE_CMD_SENT());
|
||||||
.catch((error: Error) => {
|
})
|
||||||
toast.error(error.message);
|
.catch((error: Error) => {
|
||||||
})
|
toast.error(error.message);
|
||||||
.finally(() => {
|
})
|
||||||
setDeviceValueDialogOpen(false);
|
.finally(() => {
|
||||||
setSelectedDashboardItem(undefined);
|
setDeviceValueDialogOpen(false);
|
||||||
});
|
setSelectedDashboardItem(undefined);
|
||||||
};
|
});
|
||||||
|
},
|
||||||
|
[selectedDashboardItem, sendDeviceValue, LL]
|
||||||
|
);
|
||||||
|
|
||||||
const dashboard_theme = useTheme({
|
const dashboard_theme = useMemo(
|
||||||
Table: `
|
() =>
|
||||||
|
useTheme({
|
||||||
|
Table: `
|
||||||
--data-table-library_grid-template-columns: minmax(80px, auto) 120px 32px;
|
--data-table-library_grid-template-columns: minmax(80px, auto) 120px 32px;
|
||||||
`,
|
`,
|
||||||
BaseRow: `
|
BaseRow: `
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
.td {
|
.td {
|
||||||
height: 28px;
|
height: 28px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Row: `
|
Row: `
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
&:nth-of-type(odd) .td {
|
&:nth-of-type(odd) .td {
|
||||||
@@ -114,7 +119,7 @@ const Dashboard = () => {
|
|||||||
background-color: #177ac9;
|
background-color: #177ac9;
|
||||||
},
|
},
|
||||||
`,
|
`,
|
||||||
BaseCell: `
|
BaseCell: `
|
||||||
&:nth-of-type(2) {
|
&:nth-of-type(2) {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
@@ -122,12 +127,14 @@ const Dashboard = () => {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
});
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const tree = useTree(
|
const tree = useTree(
|
||||||
{ nodes: data.nodes },
|
{ nodes: data.nodes },
|
||||||
{
|
{
|
||||||
onChange: undefined // not used but needed
|
onChange: () => {} // not used but needed
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
treeIcon: {
|
treeIcon: {
|
||||||
@@ -162,28 +169,31 @@ const Dashboard = () => {
|
|||||||
: tree.fns.onRemoveAll(); // collapse tree
|
: tree.fns.onRemoveAll(); // collapse tree
|
||||||
}, [parentNodes]);
|
}, [parentNodes]);
|
||||||
|
|
||||||
const showType = (n?: string, t?: number) => {
|
const showType = useCallback(
|
||||||
// if we have a name show it
|
(n?: string, t?: number) => {
|
||||||
if (n) {
|
// if we have a name show it
|
||||||
return n;
|
if (n) {
|
||||||
}
|
return n;
|
||||||
if (t) {
|
|
||||||
// otherwise pick translation based on type
|
|
||||||
switch (t) {
|
|
||||||
case DeviceType.CUSTOM:
|
|
||||||
return LL.CUSTOM_ENTITIES(0);
|
|
||||||
case DeviceType.ANALOGSENSOR:
|
|
||||||
return LL.ANALOG_SENSORS();
|
|
||||||
case DeviceType.TEMPERATURESENSOR:
|
|
||||||
return LL.TEMP_SENSORS();
|
|
||||||
case DeviceType.SCHEDULER:
|
|
||||||
return LL.SCHEDULER();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if (t) {
|
||||||
return '';
|
// otherwise pick translation based on type
|
||||||
};
|
switch (t) {
|
||||||
|
case DeviceType.CUSTOM:
|
||||||
|
return LL.CUSTOM_ENTITIES(0);
|
||||||
|
case DeviceType.ANALOGSENSOR:
|
||||||
|
return LL.ANALOG_SENSORS();
|
||||||
|
case DeviceType.TEMPERATURESENSOR:
|
||||||
|
return LL.TEMP_SENSORS();
|
||||||
|
case DeviceType.SCHEDULER:
|
||||||
|
return LL.SCHEDULER();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
[LL]
|
||||||
|
);
|
||||||
|
|
||||||
const showName = (di: DashboardItem) => {
|
const showName = (di: DashboardItem) => {
|
||||||
if (di.id < 100) {
|
if (di.id < 100) {
|
||||||
@@ -201,20 +211,24 @@ const Dashboard = () => {
|
|||||||
if (di.dv) {
|
if (di.dv) {
|
||||||
return <span>{di.dv.id.slice(2)}</span>;
|
return <span>{di.dv.id.slice(2)}</span>;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasMask = (id: string, mask: number) =>
|
const hasMask = (id: string, mask: number) =>
|
||||||
(parseInt(id.slice(0, 2), 16) & mask) === mask;
|
(parseInt(id.slice(0, 2), 16) & mask) === mask;
|
||||||
|
|
||||||
const editDashboardValue = (di: DashboardItem) => {
|
const editDashboardValue = useCallback(
|
||||||
if (me.admin && di.dv?.c) {
|
(di: DashboardItem) => {
|
||||||
setSelectedDashboardItem(di);
|
if (me.admin && di.dv?.c) {
|
||||||
setDeviceValueDialogOpen(true);
|
setSelectedDashboardItem(di);
|
||||||
}
|
setDeviceValueDialogOpen(true);
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
[me.admin]
|
||||||
|
);
|
||||||
|
|
||||||
const handleShowAll = (
|
const handleShowAll = (
|
||||||
event: React.MouseEvent<HTMLElement>,
|
_event: React.MouseEvent<HTMLElement>,
|
||||||
toggle: boolean | null
|
toggle: boolean | null
|
||||||
) => {
|
) => {
|
||||||
if (toggle !== null) {
|
if (toggle !== null) {
|
||||||
@@ -225,7 +239,9 @@ const Dashboard = () => {
|
|||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={fetchDashboard} errorMessage={error?.message} />;
|
return (
|
||||||
|
<FormLoader onRetry={fetchDashboard} errorMessage={error?.message || ''} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasFavEntities = data.nodes.filter(
|
const hasFavEntities = data.nodes.filter(
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
List,
|
List,
|
||||||
@@ -329,13 +329,16 @@ const Devices = () => {
|
|||||||
|
|
||||||
const handleDownloadCsv = () => {
|
const handleDownloadCsv = () => {
|
||||||
const deviceIndex = coreData.devices.findIndex(
|
const deviceIndex = coreData.devices.findIndex(
|
||||||
(d) => d.id === device_select.state.id
|
(d: Device) => d.id === device_select.state.id
|
||||||
);
|
);
|
||||||
if (deviceIndex === -1) {
|
if (deviceIndex === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename =
|
const selectedDevice = coreData.devices[deviceIndex];
|
||||||
coreData.devices[deviceIndex].tn + '_' + coreData.devices[deviceIndex].n;
|
if (!selectedDevice) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filename = selectedDevice.tn + '_' + selectedDevice.n;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -350,7 +353,7 @@ const Devices = () => {
|
|||||||
{
|
{
|
||||||
accessor: (dv: DeviceValue) =>
|
accessor: (dv: DeviceValue) =>
|
||||||
dv.u !== undefined && DeviceValueUOM_s[dv.u]
|
dv.u !== undefined && DeviceValueUOM_s[dv.u]
|
||||||
? DeviceValueUOM_s[dv.u].replace(/[^a-zA-Z0-9]/g, '')
|
? DeviceValueUOM_s[dv.u]?.replace(/[^a-zA-Z0-9]/g, '')
|
||||||
: '',
|
: '',
|
||||||
name: 'UoM'
|
name: 'UoM'
|
||||||
},
|
},
|
||||||
@@ -373,7 +376,9 @@ const Devices = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const data = onlyFav
|
const data = onlyFav
|
||||||
? deviceData.nodes.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE))
|
? deviceData.nodes.filter((dv: DeviceValue) =>
|
||||||
|
hasMask(dv.id, DeviceEntityMask.DV_FAVORITE)
|
||||||
|
)
|
||||||
: deviceData.nodes;
|
: deviceData.nodes;
|
||||||
|
|
||||||
const csvData = data.reduce(
|
const csvData = data.reduce(
|
||||||
@@ -433,10 +438,14 @@ const Devices = () => {
|
|||||||
const renderDeviceDetails = () => {
|
const renderDeviceDetails = () => {
|
||||||
if (showDeviceInfo) {
|
if (showDeviceInfo) {
|
||||||
const deviceIndex = coreData.devices.findIndex(
|
const deviceIndex = coreData.devices.findIndex(
|
||||||
(d) => d.id === device_select.state.id
|
(d: Device) => d.id === device_select.state.id
|
||||||
);
|
);
|
||||||
if (deviceIndex === -1) {
|
if (deviceIndex === -1) {
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
const deviceDetails = coreData.devices[deviceIndex];
|
||||||
|
if (!deviceDetails) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -449,47 +458,35 @@ const Devices = () => {
|
|||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<List dense={true}>
|
<List dense={true}>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText primary={LL.TYPE(0)} secondary={deviceDetails.tn} />
|
||||||
primary={LL.TYPE(0)}
|
|
||||||
secondary={coreData.devices[deviceIndex].tn}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText primary={LL.NAME(0)} secondary={deviceDetails.n} />
|
||||||
primary={LL.NAME(0)}
|
|
||||||
secondary={coreData.devices[deviceIndex].n}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{coreData.devices[deviceIndex].t !== DeviceType.CUSTOM && (
|
{deviceDetails.t !== DeviceType.CUSTOM && (
|
||||||
<>
|
<>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText primary={LL.BRAND()} secondary={deviceDetails.b} />
|
||||||
primary={LL.BRAND()}
|
|
||||||
secondary={coreData.devices[deviceIndex].b}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.ID_OF(LL.DEVICE())}
|
primary={LL.ID_OF(LL.DEVICE())}
|
||||||
secondary={
|
secondary={
|
||||||
'0x' +
|
'0x' +
|
||||||
(
|
('00' + deviceDetails.d.toString(16).toUpperCase()).slice(-2)
|
||||||
'00' +
|
|
||||||
coreData.devices[deviceIndex].d.toString(16).toUpperCase()
|
|
||||||
).slice(-2)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.ID_OF(LL.PRODUCT())}
|
primary={LL.ID_OF(LL.PRODUCT())}
|
||||||
secondary={coreData.devices[deviceIndex].p}
|
secondary={deviceDetails.p}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.VERSION()}
|
primary={LL.VERSION()}
|
||||||
secondary={coreData.devices[deviceIndex].v}
|
secondary={deviceDetails.v}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</>
|
</>
|
||||||
@@ -508,6 +505,7 @@ const Devices = () => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderCoreData = () => (
|
const renderCoreData = () => (
|
||||||
@@ -598,19 +596,26 @@ const Devices = () => {
|
|||||||
|
|
||||||
const shown_data = onlyFav
|
const shown_data = onlyFav
|
||||||
? deviceData.nodes.filter(
|
? deviceData.nodes.filter(
|
||||||
(dv) =>
|
(dv: DeviceValue) =>
|
||||||
hasMask(dv.id, DeviceEntityMask.DV_FAVORITE) &&
|
hasMask(dv.id, DeviceEntityMask.DV_FAVORITE) &&
|
||||||
dv.id.slice(2).includes(search)
|
dv.id.slice(2).toLowerCase().includes(search.toLowerCase())
|
||||||
)
|
)
|
||||||
: deviceData.nodes.filter((dv) => dv.id.slice(2).includes(search));
|
: deviceData.nodes.filter((dv: DeviceValue) =>
|
||||||
|
dv.id.slice(2).toLowerCase().includes(search.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
const deviceIndex = coreData.devices.findIndex(
|
const deviceIndex = coreData.devices.findIndex(
|
||||||
(d) => d.id === device_select.state.id
|
(d: Device) => d.id === device_select.state.id
|
||||||
);
|
);
|
||||||
if (deviceIndex === -1) {
|
if (deviceIndex === -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const deviceInfo = coreData.devices[deviceIndex];
|
||||||
|
if (!deviceInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, height] = size;
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@@ -621,15 +626,15 @@ const Devices = () => {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
top: 64,
|
top: 64,
|
||||||
zIndex: 'modal',
|
zIndex: 'modal',
|
||||||
maxHeight: () => size[1] - 126,
|
maxHeight: () => (height || 0) - 126,
|
||||||
border: '1px solid #177ac9'
|
border: '1px solid #177ac9'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ p: 1 }}>
|
<Box sx={{ p: 1 }}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography noWrap variant="subtitle1" color="warning.main">
|
<Typography noWrap variant="subtitle1" color="warning.main">
|
||||||
{coreData.devices[deviceIndex].n} (
|
{deviceInfo.n} (
|
||||||
{coreData.devices[deviceIndex].tn})
|
{deviceInfo.tn})
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid justifyContent="flex-end">
|
<Grid justifyContent="flex-end">
|
||||||
<ButtonTooltip title={LL.CLOSE()}>
|
<ButtonTooltip title={LL.CLOSE()}>
|
||||||
@@ -699,7 +704,7 @@ const Devices = () => {
|
|||||||
' ' +
|
' ' +
|
||||||
shown_data.length +
|
shown_data.length +
|
||||||
'/' +
|
'/' +
|
||||||
coreData.devices[deviceIndex].e +
|
deviceInfo.e +
|
||||||
' ' +
|
' ' +
|
||||||
LL.ENTITIES(shown_data.length)}
|
LL.ENTITIES(shown_data.length)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
FormHelperText,
|
FormHelperText,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -120,7 +120,7 @@ const DevicesDialog = ({
|
|||||||
{editItem.l ? (
|
{editItem.l ? (
|
||||||
<TextField
|
<TextField
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(0)}
|
// label={LL.VALUE(0)}
|
||||||
value={editItem.v}
|
value={editItem.v}
|
||||||
disabled={!writeable}
|
disabled={!writeable}
|
||||||
sx={{ width: '30ch' }}
|
sx={{ width: '30ch' }}
|
||||||
@@ -135,7 +135,7 @@ const DevicesDialog = ({
|
|||||||
</TextField>
|
</TextField>
|
||||||
) : editItem.s || editItem.u !== DeviceValueUOM.NONE ? (
|
) : editItem.s || editItem.u !== DeviceValueUOM.NONE ? (
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(0)}
|
label={LL.VALUE(0)}
|
||||||
value={numberValue(Math.round((editItem.v as number) * 10) / 10)}
|
value={numberValue(Math.round((editItem.v as number) * 10) / 10)}
|
||||||
@@ -159,7 +159,7 @@ const DevicesDialog = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="v"
|
name="v"
|
||||||
label={LL.VALUE(0)}
|
label={LL.VALUE(0)}
|
||||||
value={editItem.v}
|
value={editItem.v}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const EntityMaskToggle = ({ onUpdate, de }: EntityMaskToggleProps) => {
|
|||||||
size="small"
|
size="small"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
value={getMaskString(de.m)}
|
value={getMaskString(de.m)}
|
||||||
onChange={(event, mask: string[]) => {
|
onChange={(_event, mask: string[]) => {
|
||||||
de.m = getMaskNumber(mask);
|
de.m = getMaskNumber(mask);
|
||||||
if (de.n === '' && de.m & DeviceEntityMask.DV_READONLY) {
|
if (de.n === '' && de.m & DeviceEntityMask.DV_READONLY) {
|
||||||
de.m = de.m | DeviceEntityMask.DV_WEB_EXCLUDE;
|
de.m = de.m | DeviceEntityMask.DV_WEB_EXCLUDE;
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ const Help = () => {
|
|||||||
|
|
||||||
useRequest(() => callAction({ action: 'getCustomSupport' })).onSuccess((event) => {
|
useRequest(() => callAction({ action: 'getCustomSupport' })).onSuccess((event) => {
|
||||||
if (event && event.data && Object.keys(event.data).length !== 0) {
|
if (event && event.data && Object.keys(event.data).length !== 0) {
|
||||||
const data = event.data.Support;
|
const data = (event.data as { Support: { img_url?: string; html?: string[] } })
|
||||||
|
.Support;
|
||||||
if (data.img_url) {
|
if (data.img_url) {
|
||||||
setCustomSupportIMG(data.img_url);
|
setCustomSupportIMG(data.img_url);
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ const Help = () => {
|
|||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
})
|
})
|
||||||
.onError((error) => {
|
.onError((error) => {
|
||||||
toast.error(error.message);
|
toast.error(String(error.error?.message || 'An error occurred'));
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -133,13 +133,15 @@ const Modules = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveModules = async () => {
|
const saveModules = async () => {
|
||||||
await updateModules({
|
await Promise.all(
|
||||||
modules: modules.map((condensed_mi) => ({
|
modules.map((condensed_mi: ModuleItem) =>
|
||||||
key: condensed_mi.key,
|
updateModules({
|
||||||
enabled: condensed_mi.enabled,
|
key: condensed_mi.key,
|
||||||
license: condensed_mi.license
|
enabled: condensed_mi.enabled,
|
||||||
}))
|
license: condensed_mi.license
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.MODULES_UPDATED());
|
toast.success(LL.MODULES_UPDATED());
|
||||||
})
|
})
|
||||||
@@ -154,7 +156,9 @@ const Modules = () => {
|
|||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (!modules) {
|
if (!modules) {
|
||||||
return <FormLoader onRetry={fetchModules} errorMessage={error?.message} />;
|
return (
|
||||||
|
<FormLoader onRetry={fetchModules} errorMessage={error?.message || ''} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.length === 0) {
|
if (modules.length === 0) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
TextField
|
TextField
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import { useInterval } from 'utils';
|
||||||
|
|
||||||
import { readSchedule, writeSchedule } from '../../api/app';
|
import { readSchedule, writeSchedule } from '../../api/app';
|
||||||
import SettingsSchedulerDialog from './SchedulerDialog';
|
import SettingsSchedulerDialog from './SchedulerDialog';
|
||||||
@@ -73,6 +74,12 @@ const Scheduler = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
if (numChanges === 0) {
|
||||||
|
void fetchSchedule();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const formatter = new Intl.DateTimeFormat(locale, {
|
const formatter = new Intl.DateTimeFormat(locale, {
|
||||||
weekday: 'short',
|
weekday: 'short',
|
||||||
@@ -128,8 +135,8 @@ const Scheduler = () => {
|
|||||||
const saveSchedule = async () => {
|
const saveSchedule = async () => {
|
||||||
await updateSchedule({
|
await updateSchedule({
|
||||||
schedule: schedule
|
schedule: schedule
|
||||||
.filter((si) => !si.deleted)
|
.filter((si: ScheduleItem) => !si.deleted)
|
||||||
.map((condensed_si) => ({
|
.map((condensed_si: ScheduleItem) => ({
|
||||||
id: condensed_si.id,
|
id: condensed_si.id,
|
||||||
active: condensed_si.active,
|
active: condensed_si.active,
|
||||||
flags: condensed_si.flags,
|
flags: condensed_si.flags,
|
||||||
@@ -205,7 +212,9 @@ const Scheduler = () => {
|
|||||||
|
|
||||||
const renderSchedule = () => {
|
const renderSchedule = () => {
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
return <FormLoader onRetry={fetchSchedule} errorMessage={error?.message} />;
|
return (
|
||||||
|
<FormLoader onRetry={fetchSchedule} errorMessage={error?.message || ''} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dayBox = (si: ScheduleItem, flag: number) => (
|
const dayBox = (si: ScheduleItem, flag: number) => (
|
||||||
@@ -244,8 +253,8 @@ const Scheduler = () => {
|
|||||||
<Table
|
<Table
|
||||||
data={{
|
data={{
|
||||||
nodes: schedule
|
nodes: schedule
|
||||||
.filter((si) => !si.deleted)
|
.filter((si: ScheduleItem) => !si.deleted)
|
||||||
.sort((a, b) => a.flags - b.flags)
|
.sort((a: ScheduleItem, b: ScheduleItem) => a.flags - b.flags)
|
||||||
}}
|
}}
|
||||||
theme={schedule_theme}
|
theme={schedule_theme}
|
||||||
layout={{ custom: true }}
|
layout={{ custom: true }}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
TextField,
|
TextField,
|
||||||
ToggleButton,
|
ToggleButton,
|
||||||
ToggleButtonGroup,
|
ToggleButtonGroup,
|
||||||
@@ -144,7 +144,10 @@ const SchedulerDialog = ({
|
|||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClose = (_event, reason: 'backdropClick' | 'escapeKeyDown') => {
|
const handleClose = (
|
||||||
|
_event: React.SyntheticEvent,
|
||||||
|
reason: 'backdropClick' | 'escapeKeyDown'
|
||||||
|
) => {
|
||||||
if (reason !== 'backdropClick') {
|
if (reason !== 'backdropClick') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -325,7 +328,7 @@ const SchedulerDialog = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="cmd"
|
name="cmd"
|
||||||
label={LL.COMMAND(0)}
|
label={LL.COMMAND(0)}
|
||||||
multiline
|
multiline
|
||||||
@@ -344,7 +347,7 @@ const SchedulerDialog = ({
|
|||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="name"
|
name="name"
|
||||||
label={LL.NAME(0) + ' (' + LL.OPTIONAL() + ')'}
|
label={LL.NAME(0) + ' (' + LL.OPTIONAL() + ')'}
|
||||||
value={editItem.name}
|
value={editItem.name}
|
||||||
|
|||||||
@@ -439,7 +439,8 @@ const Sensors = () => {
|
|||||||
<Cell>{a.n}</Cell>
|
<Cell>{a.n}</Cell>
|
||||||
<Cell stiff>{AnalogTypeNames[a.t]} </Cell>
|
<Cell stiff>{AnalogTypeNames[a.t]} </Cell>
|
||||||
{(a.t === AnalogType.DIGITAL_OUT && a.g !== 25 && a.g !== 26) ||
|
{(a.t === AnalogType.DIGITAL_OUT && a.g !== 25 && a.g !== 26) ||
|
||||||
a.t === AnalogType.DIGITAL_IN ? (
|
a.t === AnalogType.DIGITAL_IN ||
|
||||||
|
a.t === AnalogType.PULSE ? (
|
||||||
<Cell stiff>{a.v ? LL.ON() : LL.OFF()}</Cell>
|
<Cell stiff>{a.v ? LL.ON() : LL.OFF()}</Cell>
|
||||||
) : (
|
) : (
|
||||||
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
<Cell stiff>{a.t ? formatValue(a.v, a.u) : ''}</Cell>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -57,7 +57,10 @@ const SensorsAnalogDialog = ({
|
|||||||
}
|
}
|
||||||
}, [open, selectedItem]);
|
}, [open, selectedItem]);
|
||||||
|
|
||||||
const handleClose = (_event, reason: 'backdropClick' | 'escapeKeyDown') => {
|
const handleClose = (
|
||||||
|
_event: React.SyntheticEvent,
|
||||||
|
reason: 'backdropClick' | 'escapeKeyDown'
|
||||||
|
) => {
|
||||||
if (reason !== 'backdropClick') {
|
if (reason !== 'backdropClick') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -88,7 +91,7 @@ const SensorsAnalogDialog = ({
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="g"
|
name="g"
|
||||||
label="GPIO"
|
label="GPIO"
|
||||||
sx={{ width: '11ch' }}
|
sx={{ width: '11ch' }}
|
||||||
@@ -107,7 +110,7 @@ const SensorsAnalogDialog = ({
|
|||||||
)}
|
)}
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="n"
|
name="n"
|
||||||
label={LL.NAME(0)}
|
label={LL.NAME(0)}
|
||||||
value={editItem.n}
|
value={editItem.n}
|
||||||
@@ -132,7 +135,9 @@ const SensorsAnalogDialog = ({
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
{((editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE) ||
|
||||||
|
(editItem.t >= AnalogType.FREQ_0 &&
|
||||||
|
editItem.t <= AnalogType.FREQ_2)) && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="u"
|
name="u"
|
||||||
@@ -171,6 +176,27 @@ const SensorsAnalogDialog = ({
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
{editItem.t === AnalogType.NTC && (
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
name="o"
|
||||||
|
label={LL.OFFSET()}
|
||||||
|
value={numberValue(editItem.o)}
|
||||||
|
sx={{ width: '11ch' }}
|
||||||
|
type="number"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
slotProps={{
|
||||||
|
input: {
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">°C</InputAdornment>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
htmlInput: { min: '-20', max: '20', step: '0.1' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
{editItem.t === AnalogType.COUNTER && (
|
{editItem.t === AnalogType.COUNTER && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -187,6 +213,19 @@ const SensorsAnalogDialog = ({
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
{editItem.t === AnalogType.RGB && (
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
name="o"
|
||||||
|
label={'RGB ' + LL.VALUE(0)}
|
||||||
|
value={numberValue(editItem.o)}
|
||||||
|
type="number"
|
||||||
|
sx={{ width: '11ch' }}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
{editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -314,6 +353,42 @@ const SensorsAnalogDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{editItem.t === AnalogType.PULSE && (
|
||||||
|
<>
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
name="o"
|
||||||
|
label={LL.POLARITY()}
|
||||||
|
value={editItem.o}
|
||||||
|
sx={{ width: '11ch' }}
|
||||||
|
select
|
||||||
|
onChange={updateFormValue}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>{LL.ACTIVEHIGH()}</MenuItem>
|
||||||
|
<MenuItem value={1}>{LL.ACTIVELOW()}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
name="f"
|
||||||
|
label="Pulse"
|
||||||
|
value={numberValue(editItem.f)}
|
||||||
|
type="number"
|
||||||
|
sx={{ width: '15ch' }}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
slotProps={{
|
||||||
|
input: {
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">s</InputAdornment>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
htmlInput: { min: '0', max: '10000', step: '0.1' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
TextField,
|
TextField,
|
||||||
Typography
|
Typography
|
||||||
@@ -52,7 +52,10 @@ const SensorsTemperatureDialog = ({
|
|||||||
}
|
}
|
||||||
}, [open, selectedItem]);
|
}, [open, selectedItem]);
|
||||||
|
|
||||||
const handleClose = (_event, reason: 'backdropClick' | 'escapeKeyDown') => {
|
const handleClose = (
|
||||||
|
_event: React.SyntheticEvent,
|
||||||
|
reason: 'backdropClick' | 'escapeKeyDown'
|
||||||
|
) => {
|
||||||
if (reason !== 'backdropClick') {
|
if (reason !== 'backdropClick') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,7 @@ const SensorsTemperatureDialog = ({
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="n"
|
name="n"
|
||||||
label={LL.NAME(0)}
|
label={LL.NAME(0)}
|
||||||
value={editItem.n}
|
value={editItem.n}
|
||||||
|
|||||||
@@ -188,7 +188,8 @@ export enum DeviceValueUOM {
|
|||||||
VOLTS,
|
VOLTS,
|
||||||
MBAR,
|
MBAR,
|
||||||
LH,
|
LH,
|
||||||
CTKWH
|
CTKWH,
|
||||||
|
HZ
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeviceValueUOM_s = [
|
export const DeviceValueUOM_s = [
|
||||||
@@ -218,7 +219,8 @@ export const DeviceValueUOM_s = [
|
|||||||
'V',
|
'V',
|
||||||
'mbar',
|
'mbar',
|
||||||
'l/h',
|
'l/h',
|
||||||
'ct/kWh'
|
'ct/kWh',
|
||||||
|
'Hz'
|
||||||
];
|
];
|
||||||
|
|
||||||
export enum AnalogType {
|
export enum AnalogType {
|
||||||
@@ -232,20 +234,32 @@ export enum AnalogType {
|
|||||||
DIGITAL_OUT = 6,
|
DIGITAL_OUT = 6,
|
||||||
PWM_0 = 7,
|
PWM_0 = 7,
|
||||||
PWM_1 = 8,
|
PWM_1 = 8,
|
||||||
PWM_2 = 9
|
PWM_2 = 9,
|
||||||
|
NTC = 10,
|
||||||
|
RGB = 11,
|
||||||
|
PULSE = 12,
|
||||||
|
FREQ_0 = 13,
|
||||||
|
FREQ_1 = 14,
|
||||||
|
FREQ_2 = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AnalogTypeNames = [
|
export const AnalogTypeNames = [
|
||||||
'(disabled)',
|
'(disabled)',
|
||||||
'Digital In',
|
'Digital In',
|
||||||
'Counter',
|
'Counter',
|
||||||
'ADC',
|
'ADC In',
|
||||||
'Timer',
|
'Timer',
|
||||||
'Rate',
|
'Rate',
|
||||||
'Digital Out',
|
'Digital Out',
|
||||||
'PWM 0',
|
'PWM 0',
|
||||||
'PWM 1',
|
'PWM 1',
|
||||||
'PWM 2'
|
'PWM 2',
|
||||||
|
'NTC Temp.',
|
||||||
|
'RGB Led',
|
||||||
|
'Pulse',
|
||||||
|
'Freq 0',
|
||||||
|
'Freq 1',
|
||||||
|
'Freq 2'
|
||||||
];
|
];
|
||||||
|
|
||||||
type BoardProfiles = Record<string, string>;
|
type BoardProfiles = Record<string, string>;
|
||||||
@@ -255,6 +269,7 @@ export const BOARD_PROFILES: BoardProfiles = {
|
|||||||
S32S3: 'BBQKees Gateway S3',
|
S32S3: 'BBQKees Gateway S3',
|
||||||
E32: 'BBQKees Gateway E32',
|
E32: 'BBQKees Gateway E32',
|
||||||
E32V2: 'BBQKees Gateway E32 V2',
|
E32V2: 'BBQKees Gateway E32 V2',
|
||||||
|
E32V2_2: 'BBQKees Gateway E32 V2.2',
|
||||||
NODEMCU: 'NodeMCU 32S',
|
NODEMCU: 'NodeMCU 32S',
|
||||||
'MH-ET': 'MH-ET Live D1 Mini',
|
'MH-ET': 'MH-ET Live D1 Mini',
|
||||||
LOLIN: 'Lolin D32',
|
LOLIN: 'Lolin D32',
|
||||||
@@ -380,6 +395,7 @@ export interface EntityItem {
|
|||||||
value_type: number;
|
value_type: number;
|
||||||
value?: unknown;
|
value?: unknown;
|
||||||
writeable: boolean;
|
writeable: boolean;
|
||||||
|
hide: boolean;
|
||||||
deleted?: boolean;
|
deleted?: boolean;
|
||||||
o_id?: number;
|
o_id?: number;
|
||||||
o_ram?: number;
|
o_ram?: number;
|
||||||
@@ -393,6 +409,7 @@ export interface EntityItem {
|
|||||||
o_deleted?: boolean;
|
o_deleted?: boolean;
|
||||||
o_writeable?: boolean;
|
o_writeable?: boolean;
|
||||||
o_value?: unknown;
|
o_value?: unknown;
|
||||||
|
o_hide?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Entities {
|
export interface Entities {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type {
|
|||||||
|
|
||||||
export const GPIO_VALIDATOR = {
|
export const GPIO_VALIDATOR = {
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: number,
|
value: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -36,7 +36,7 @@ export const GPIO_VALIDATOR = {
|
|||||||
|
|
||||||
export const GPIO_VALIDATORR = {
|
export const GPIO_VALIDATORR = {
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: number,
|
value: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -60,7 +60,7 @@ export const GPIO_VALIDATORR = {
|
|||||||
|
|
||||||
export const GPIO_VALIDATORC3 = {
|
export const GPIO_VALIDATORC3 = {
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: number,
|
value: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -74,7 +74,7 @@ export const GPIO_VALIDATORC3 = {
|
|||||||
|
|
||||||
export const GPIO_VALIDATORS2 = {
|
export const GPIO_VALIDATORS2 = {
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: number,
|
value: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -94,7 +94,7 @@ export const GPIO_VALIDATORS2 = {
|
|||||||
|
|
||||||
export const GPIO_VALIDATORS3 = {
|
export const GPIO_VALIDATORS3 = {
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: number,
|
value: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -279,7 +279,7 @@ export const createSettingsValidator = (settings: Settings) =>
|
|||||||
|
|
||||||
export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) => ({
|
export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) => ({
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
name: string,
|
name: string,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -324,7 +324,7 @@ export const uniqueCustomNameValidator = (
|
|||||||
o_name?: string
|
o_name?: string
|
||||||
) => ({
|
) => ({
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
name: string,
|
name: string,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -353,7 +353,7 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
|
|||||||
device_id: [
|
device_id: [
|
||||||
{
|
{
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: string,
|
value: string,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -367,7 +367,7 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
|
|||||||
type_id: [
|
type_id: [
|
||||||
{
|
{
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: string,
|
value: string,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -389,7 +389,7 @@ export const uniqueTemperatureNameValidator = (
|
|||||||
sensors: TemperatureSensor[],
|
sensors: TemperatureSensor[],
|
||||||
o_name?: string
|
o_name?: string
|
||||||
) => ({
|
) => ({
|
||||||
validator(rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
validator(_rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
||||||
if (
|
if (
|
||||||
(o_name === undefined || o_name.toLowerCase() !== n.toLowerCase()) &&
|
(o_name === undefined || o_name.toLowerCase() !== n.toLowerCase()) &&
|
||||||
n !== '' &&
|
n !== '' &&
|
||||||
@@ -419,7 +419,7 @@ export const temperatureSensorItemValidation = (
|
|||||||
|
|
||||||
export const isGPIOUniqueValidator = (sensors: AnalogSensor[]) => ({
|
export const isGPIOUniqueValidator = (sensors: AnalogSensor[]) => ({
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
gpio: number,
|
gpio: number,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -435,7 +435,7 @@ export const uniqueAnalogNameValidator = (
|
|||||||
sensors: AnalogSensor[],
|
sensors: AnalogSensor[],
|
||||||
o_name?: string
|
o_name?: string
|
||||||
) => ({
|
) => ({
|
||||||
validator(rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
validator(_rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
||||||
if (
|
if (
|
||||||
(o_name === undefined || o_name.toLowerCase() !== n.toLowerCase()) &&
|
(o_name === undefined || o_name.toLowerCase() !== n.toLowerCase()) &&
|
||||||
n !== '' &&
|
n !== '' &&
|
||||||
@@ -482,7 +482,7 @@ export const deviceValueItemValidation = (dv: DeviceValue) =>
|
|||||||
{ required: true, message: 'Value is required' },
|
{ required: true, message: 'Value is required' },
|
||||||
{
|
{
|
||||||
validator(
|
validator(
|
||||||
rule: InternalRuleItem,
|
_rule: InternalRuleItem,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ const APSettings = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -80,7 +80,7 @@ const APSettings = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="provision_mode"
|
name="provision_mode"
|
||||||
label={LL.AP_PROVIDE() + '...'}
|
label={LL.AP_PROVIDE() + '...'}
|
||||||
value={data.provision_mode}
|
value={data.provision_mode}
|
||||||
@@ -103,7 +103,7 @@ const APSettings = () => {
|
|||||||
{isAPEnabled(data) && (
|
{isAPEnabled(data) && (
|
||||||
<>
|
<>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="ssid"
|
name="ssid"
|
||||||
label={LL.ACCESS_POINT(2) + ' SSID'}
|
label={LL.ACCESS_POINT(2) + ' SSID'}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -113,7 +113,7 @@ const APSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="password"
|
name="password"
|
||||||
label={LL.ACCESS_POINT(2) + ' ' + LL.PASSWORD()}
|
label={LL.ACCESS_POINT(2) + ' ' + LL.PASSWORD()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -123,7 +123,7 @@ const APSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="channel"
|
name="channel"
|
||||||
label={LL.AP_PREFERRED_CHANNEL()}
|
label={LL.AP_PREFERRED_CHANNEL()}
|
||||||
value={numberValue(data.channel)}
|
value={numberValue(data.channel)}
|
||||||
@@ -151,7 +151,7 @@ const APSettings = () => {
|
|||||||
label={LL.AP_HIDE_SSID()}
|
label={LL.AP_HIDE_SSID()}
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="max_clients"
|
name="max_clients"
|
||||||
label={LL.AP_MAX_CLIENTS()}
|
label={LL.AP_MAX_CLIENTS()}
|
||||||
value={numberValue(data.max_clients)}
|
value={numberValue(data.max_clients)}
|
||||||
@@ -169,7 +169,7 @@ const APSettings = () => {
|
|||||||
))}
|
))}
|
||||||
</ValidatedTextField>
|
</ValidatedTextField>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="local_ip"
|
name="local_ip"
|
||||||
label={LL.AP_LOCAL_IP()}
|
label={LL.AP_LOCAL_IP()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -179,7 +179,7 @@ const APSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="gateway_ip"
|
name="gateway_ip"
|
||||||
label={LL.NETWORK_GATEWAY()}
|
label={LL.NETWORK_GATEWAY()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -189,7 +189,7 @@ const APSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="subnet_mask"
|
name="subnet_mask"
|
||||||
label={LL.NETWORK_SUBNET()}
|
label={LL.NETWORK_SUBNET()}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Divider,
|
Divider,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -75,7 +75,7 @@ const ApplicationSettings = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
@@ -135,7 +135,7 @@ const ApplicationSettings = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data || !hardwareData) {
|
if (!data || !hardwareData) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -219,7 +219,7 @@ const ApplicationSettings = () => {
|
|||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="modbus_max_clients"
|
name="modbus_max_clients"
|
||||||
label={LL.AP_MAX_CLIENTS()}
|
label={LL.AP_MAX_CLIENTS()}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -231,7 +231,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="modbus_port"
|
name="modbus_port"
|
||||||
label="Port"
|
label="Port"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -243,7 +243,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="modbus_timeout"
|
name="modbus_timeout"
|
||||||
label="Timeout"
|
label="Timeout"
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -273,7 +273,7 @@ const ApplicationSettings = () => {
|
|||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="syslog_host"
|
name="syslog_host"
|
||||||
label="Host"
|
label="Host"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -284,7 +284,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="syslog_port"
|
name="syslog_port"
|
||||||
label="Port"
|
label="Port"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -315,7 +315,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="syslog_mark_interval"
|
name="syslog_mark_interval"
|
||||||
label={LL.MARK_INTERVAL()}
|
label={LL.MARK_INTERVAL()}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -485,7 +485,7 @@ const ApplicationSettings = () => {
|
|||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="rx_gpio"
|
name="rx_gpio"
|
||||||
label={LL.GPIO_OF('Rx')}
|
label={LL.GPIO_OF('Rx')}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -498,7 +498,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="tx_gpio"
|
name="tx_gpio"
|
||||||
label={LL.GPIO_OF('Tx')}
|
label={LL.GPIO_OF('Tx')}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -511,7 +511,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="pbutton_gpio"
|
name="pbutton_gpio"
|
||||||
label={LL.GPIO_OF(LL.BUTTON())}
|
label={LL.GPIO_OF(LL.BUTTON())}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -524,7 +524,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="dallas_gpio"
|
name="dallas_gpio"
|
||||||
label={
|
label={
|
||||||
LL.GPIO_OF(LL.TEMPERATURE()) + ' (0=' + LL.DISABLED(1) + ')'
|
LL.GPIO_OF(LL.TEMPERATURE()) + ' (0=' + LL.DISABLED(1) + ')'
|
||||||
@@ -539,7 +539,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="led_gpio"
|
name="led_gpio"
|
||||||
label={LL.GPIO_OF('LED') + ' (0=' + LL.DISABLED(1) + ')'}
|
label={LL.GPIO_OF('LED') + ' (0=' + LL.DISABLED(1) + ')'}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -554,7 +554,7 @@ const ApplicationSettings = () => {
|
|||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="led_type"
|
name="led_type"
|
||||||
label={'LED ' + LL.TYPE()}
|
label={'LED ' + LL.TYPE(0)}
|
||||||
value={data.led_type}
|
value={data.led_type}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -743,7 +743,7 @@ const ApplicationSettings = () => {
|
|||||||
{data.remote_timeout_en && (
|
{data.remote_timeout_en && (
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="remote_timeout"
|
name="remote_timeout"
|
||||||
label={LL.REMOTE_TIMEOUT()}
|
label={LL.REMOTE_TIMEOUT()}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -783,7 +783,7 @@ const ApplicationSettings = () => {
|
|||||||
{data.shower_timer && (
|
{data.shower_timer && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="shower_min_duration"
|
name="shower_min_duration"
|
||||||
label={LL.MIN_DURATION()}
|
label={LL.MIN_DURATION()}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -801,7 +801,7 @@ const ApplicationSettings = () => {
|
|||||||
<>
|
<>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="shower_alert_trigger"
|
name="shower_alert_trigger"
|
||||||
label={LL.TRIGGER_TIME()}
|
label={LL.TRIGGER_TIME()}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -817,7 +817,7 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="shower_alert_coldshot"
|
name="shower_alert_coldshot"
|
||||||
label={LL.COLD_SHOT_DURATION()}
|
label={LL.COLD_SHOT_DURATION()}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import { Box, Button, Grid2 as Grid, Typography } from '@mui/material';
|
import { Box, Button, Grid, Typography } from '@mui/material';
|
||||||
|
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import { API, callAction } from 'api/app';
|
import { API, callAction } from 'api/app';
|
||||||
@@ -35,7 +35,7 @@ const DownloadUpload = () => {
|
|||||||
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
toast.info(LL.DOWNLOAD_SUCCESSFUL());
|
||||||
})
|
})
|
||||||
.onError((error) => {
|
.onError((error) => {
|
||||||
toast.error(error.message);
|
toast.error(String(error.error?.message || 'An error occurred'));
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
|
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
|
||||||
@@ -57,7 +57,7 @@ const DownloadUpload = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import WarningIcon from '@mui/icons-material/Warning';
|
|||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -56,7 +56,7 @@ const MqttSettings = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const SecondsInputProps = {
|
const SecondsInputProps = {
|
||||||
@@ -65,7 +65,7 @@ const MqttSettings = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -93,7 +93,7 @@ const MqttSettings = () => {
|
|||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="host"
|
name="host"
|
||||||
label={LL.ADDRESS_OF(LL.BROKER())}
|
label={LL.ADDRESS_OF(LL.BROKER())}
|
||||||
multiline
|
multiline
|
||||||
@@ -105,7 +105,7 @@ const MqttSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="port"
|
name="port"
|
||||||
label="Port"
|
label="Port"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -117,7 +117,7 @@ const MqttSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="base"
|
name="base"
|
||||||
label={LL.BASE_TOPIC()}
|
label={LL.BASE_TOPIC()}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -158,7 +158,7 @@ const MqttSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="keep_alive"
|
name="keep_alive"
|
||||||
label="Keep Alive"
|
label="Keep Alive"
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -254,109 +254,107 @@ const MqttSettings = () => {
|
|||||||
}
|
}
|
||||||
label={LL.MQTT_RESPONSE()}
|
label={LL.MQTT_RESPONSE()}
|
||||||
/>
|
/>
|
||||||
{!data.ha_enabled && (
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
name="publish_single"
|
||||||
|
checked={data.publish_single}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
disabled={data.ha_enabled}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={LL.MQTT_PUBLISH_TEXT_1()}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
{data.publish_single && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="publish_single"
|
name="publish_single2cmd"
|
||||||
checked={data.publish_single}
|
checked={data.publish_single2cmd}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label={LL.MQTT_PUBLISH_TEXT_1()}
|
label={LL.MQTT_PUBLISH_TEXT_2()}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{data.publish_single && (
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
|
<Grid>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
name="ha_enabled"
|
||||||
|
checked={data.ha_enabled}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
disabled={data.publish_single}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={LL.MQTT_PUBLISH_TEXT_3()}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
{data.ha_enabled && (
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<BlockFormControlLabel
|
<TextField
|
||||||
control={
|
name="discovery_type"
|
||||||
<Checkbox
|
label={LL.MQTT_PUBLISH_TEXT_5()}
|
||||||
name="publish_single2cmd"
|
value={data.discovery_type}
|
||||||
checked={data.publish_single2cmd}
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
margin="normal"
|
||||||
}
|
select
|
||||||
label={LL.MQTT_PUBLISH_TEXT_2()}
|
>
|
||||||
|
<MenuItem value={0}>Home Assistant</MenuItem>
|
||||||
|
<MenuItem value={1}>Domoticz</MenuItem>
|
||||||
|
<MenuItem value={2}>Domoticz (latest)</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
name="discovery_prefix"
|
||||||
|
label={LL.MQTT_PUBLISH_TEXT_4()}
|
||||||
|
variant="outlined"
|
||||||
|
value={data.discovery_prefix}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
<Grid>
|
||||||
</Grid>
|
<TextField
|
||||||
)}
|
name="entity_format"
|
||||||
{!data.publish_single && (
|
label={LL.MQTT_ENTITY_FORMAT()}
|
||||||
<Grid container spacing={2} rowSpacing={0}>
|
value={data.entity_format}
|
||||||
<Grid>
|
variant="outlined"
|
||||||
<BlockFormControlLabel
|
onChange={updateFormValue}
|
||||||
control={
|
margin="normal"
|
||||||
<Checkbox
|
select
|
||||||
name="ha_enabled"
|
>
|
||||||
checked={data.ha_enabled}
|
<MenuItem value={0}>{LL.MQTT_ENTITY_FORMAT_0()}</MenuItem>
|
||||||
onChange={updateFormValue}
|
<MenuItem value={3}>
|
||||||
/>
|
{LL.MQTT_ENTITY_FORMAT_1()} (v3.6)
|
||||||
}
|
</MenuItem>
|
||||||
label={LL.MQTT_PUBLISH_TEXT_3()}
|
<MenuItem value={4}>
|
||||||
/>
|
{LL.MQTT_ENTITY_FORMAT_2()} (v3.6)
|
||||||
</Grid>
|
</MenuItem>
|
||||||
{data.ha_enabled && (
|
<MenuItem value={1}>{LL.MQTT_ENTITY_FORMAT_1()}</MenuItem>
|
||||||
<Grid container spacing={2} rowSpacing={0}>
|
<MenuItem value={2}>{LL.MQTT_ENTITY_FORMAT_2()}</MenuItem>
|
||||||
<Grid>
|
</TextField>
|
||||||
<TextField
|
|
||||||
name="discovery_type"
|
|
||||||
label={LL.MQTT_PUBLISH_TEXT_5()}
|
|
||||||
value={data.discovery_type}
|
|
||||||
variant="outlined"
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem value={0}>Home Assistant</MenuItem>
|
|
||||||
<MenuItem value={1}>Domoticz</MenuItem>
|
|
||||||
<MenuItem value={2}>Domoticz (latest)</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid>
|
|
||||||
<TextField
|
|
||||||
name="discovery_prefix"
|
|
||||||
label={LL.MQTT_PUBLISH_TEXT_4()}
|
|
||||||
variant="outlined"
|
|
||||||
value={data.discovery_prefix}
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid>
|
|
||||||
<TextField
|
|
||||||
name="entity_format"
|
|
||||||
label={LL.MQTT_ENTITY_FORMAT()}
|
|
||||||
value={data.entity_format}
|
|
||||||
variant="outlined"
|
|
||||||
onChange={updateFormValue}
|
|
||||||
margin="normal"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem value={0}>{LL.MQTT_ENTITY_FORMAT_0()}</MenuItem>
|
|
||||||
<MenuItem value={3}>
|
|
||||||
{LL.MQTT_ENTITY_FORMAT_1()} (v3.6)
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={4}>
|
|
||||||
{LL.MQTT_ENTITY_FORMAT_2()} (v3.6)
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={1}>{LL.MQTT_ENTITY_FORMAT_1()}</MenuItem>
|
|
||||||
<MenuItem value={2}>{LL.MQTT_ENTITY_FORMAT_2()}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
</Grid>
|
||||||
</Grid>
|
)}
|
||||||
)}
|
</Grid>
|
||||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
||||||
{LL.MQTT_PUBLISH_INTERVALS()} (0=auto)
|
{LL.MQTT_PUBLISH_INTERVALS()} (0=auto)
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={2} rowSpacing={0}>
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="publish_time_heartbeat"
|
name="publish_time_heartbeat"
|
||||||
label="Heartbeat"
|
label="Heartbeat"
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@@ -442,7 +440,7 @@ const MqttSettings = () => {
|
|||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="publish_time_sensor"
|
name="publish_time_sensor"
|
||||||
label={LL.TEMP_SENSORS()}
|
label={LL.SENSORS()}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={numberValue(data.publish_time_sensor)}
|
value={numberValue(data.publish_time_sensor)}
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import { Button, Checkbox, MenuItem } from '@mui/material';
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
Typography
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
import * as NTPApi from 'api/ntp';
|
import * as NTPApi from 'api/ntp';
|
||||||
import { readNTPSettings } from 'api/ntp';
|
import { readNTPSettings } from 'api/ntp';
|
||||||
|
|
||||||
|
import { dialogStyle } from 'CustomTheme';
|
||||||
|
import { useRequest } from 'alova/client';
|
||||||
import { updateState } from 'alova/client';
|
import { updateState } from 'alova/client';
|
||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import {
|
import {
|
||||||
@@ -19,8 +34,8 @@ import {
|
|||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { NTPSettingsType } from 'types';
|
import type { NTPSettingsType, Time } from 'types';
|
||||||
import { updateValueDirty, useRest } from 'utils';
|
import { formatLocalDateTime, 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';
|
||||||
|
|
||||||
@@ -46,18 +61,101 @@ const NTPSettings = () => {
|
|||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle('NTP');
|
useLayoutTitle('NTP');
|
||||||
|
|
||||||
|
const [localTime, setLocalTime] = useState<string>('');
|
||||||
|
const [settingTime, setSettingTime] = useState<boolean>(false);
|
||||||
|
const [processing, setProcessing] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const { send: updateTime } = useRequest(
|
||||||
|
(local_time: Time) => NTPApi.updateTime(local_time),
|
||||||
|
{
|
||||||
|
immediate: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const updateFormValue = updateValueDirty(
|
const updateFormValue = updateValueDirty(
|
||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
|
|
||||||
|
const updateLocalTime = (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setLocalTime(event.target.value);
|
||||||
|
|
||||||
|
const openSetTime = () => {
|
||||||
|
setLocalTime(formatLocalDateTime(new Date()));
|
||||||
|
setSettingTime(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const configureTime = async () => {
|
||||||
|
setProcessing(true);
|
||||||
|
|
||||||
|
await updateTime({ local_time: formatLocalDateTime(new Date(localTime)) })
|
||||||
|
.then(async () => {
|
||||||
|
toast.success(LL.TIME_SET());
|
||||||
|
setSettingTime(false);
|
||||||
|
await loadData();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error(LL.PROBLEM_UPDATING());
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setProcessing(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSetTimeDialog = () => (
|
||||||
|
<Dialog
|
||||||
|
sx={dialogStyle}
|
||||||
|
open={settingTime}
|
||||||
|
onClose={() => setSettingTime(false)}
|
||||||
|
>
|
||||||
|
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
|
||||||
|
<DialogContent dividers>
|
||||||
|
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>
|
||||||
|
<Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography>
|
||||||
|
</Box>
|
||||||
|
<TextField
|
||||||
|
label={LL.LOCAL_TIME(0)}
|
||||||
|
type="datetime-local"
|
||||||
|
value={localTime}
|
||||||
|
onChange={updateLocalTime}
|
||||||
|
disabled={processing}
|
||||||
|
fullWidth
|
||||||
|
slotProps={{
|
||||||
|
inputLabel: {
|
||||||
|
shrink: true
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
startIcon={<CancelIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setSettingTime(false)}
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<AccessTimeIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={configureTime}
|
||||||
|
disabled={processing}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{LL.UPDATE()}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -92,7 +190,7 @@ const NTPSettings = () => {
|
|||||||
label={LL.ENABLE_NTP()}
|
label={LL.ENABLE_NTP()}
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="server"
|
name="server"
|
||||||
label={LL.NTP_SERVER()}
|
label={LL.NTP_SERVER()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -102,7 +200,7 @@ const NTPSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="tz_label"
|
name="tz_label"
|
||||||
label={LL.TIME_ZONE()}
|
label={LL.TIME_ZONE()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -115,6 +213,25 @@ const NTPSettings = () => {
|
|||||||
<MenuItem disabled>{LL.TIME_ZONE()}...</MenuItem>
|
<MenuItem disabled>{LL.TIME_ZONE()}...</MenuItem>
|
||||||
{timeZoneSelectItems()}
|
{timeZoneSelectItems()}
|
||||||
</ValidatedTextField>
|
</ValidatedTextField>
|
||||||
|
|
||||||
|
<Box display="flex" flexWrap="wrap">
|
||||||
|
{!data.enabled && !dirtyFlags.length && (
|
||||||
|
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||||
|
<ButtonRow>
|
||||||
|
<Button
|
||||||
|
onClick={openSetTime}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
startIcon={<AccessTimeIcon />}
|
||||||
|
>
|
||||||
|
{LL.SET_TIME(0)}
|
||||||
|
</Button>
|
||||||
|
</ButtonRow>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{renderSetTimeDialog()}
|
||||||
|
|
||||||
{dirtyFlags && dirtyFlags.length !== 0 && (
|
{dirtyFlags && dirtyFlags.length !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const Network = () => {
|
|||||||
],
|
],
|
||||||
useLocation()
|
useLocation()
|
||||||
);
|
);
|
||||||
const routerTab = matchedRoutes?.[0].route.path || false;
|
const routerTab = matchedRoutes?.[0]?.route.path || false;
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ const Network = () => {
|
|||||||
return (
|
return (
|
||||||
<WiFiConnectionContext.Provider
|
<WiFiConnectionContext.Provider
|
||||||
value={{
|
value={{
|
||||||
selectedNetwork,
|
...(selectedNetwork && { selectedNetwork }),
|
||||||
selectNetwork,
|
selectNetwork,
|
||||||
deselectNetwork
|
deselectNetwork
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ const NetworkSettings = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
@@ -113,7 +113,7 @@ const NetworkSettings = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -172,7 +172,7 @@ const NetworkSettings = () => {
|
|||||||
</List>
|
</List>
|
||||||
) : (
|
) : (
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="ssid"
|
name="ssid"
|
||||||
label={'SSID (' + LL.NETWORK_BLANK_SSID() + ')'}
|
label={'SSID (' + LL.NETWORK_BLANK_SSID() + ')'}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -183,7 +183,7 @@ const NetworkSettings = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="bssid"
|
name="bssid"
|
||||||
label={'BSSID (' + LL.NETWORK_BLANK_BSSID() + ')'}
|
label={'BSSID (' + LL.NETWORK_BLANK_BSSID() + ')'}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -194,7 +194,7 @@ const NetworkSettings = () => {
|
|||||||
/>
|
/>
|
||||||
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="password"
|
name="password"
|
||||||
label={LL.PASSWORD()}
|
label={LL.PASSWORD()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -251,7 +251,7 @@ const NetworkSettings = () => {
|
|||||||
{LL.GENERAL_OPTIONS()}
|
{LL.GENERAL_OPTIONS()}
|
||||||
</Typography>
|
</Typography>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="hostname"
|
name="hostname"
|
||||||
label={LL.HOSTNAME()}
|
label={LL.HOSTNAME()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -304,7 +304,7 @@ const NetworkSettings = () => {
|
|||||||
{data.static_ip_config && (
|
{data.static_ip_config && (
|
||||||
<>
|
<>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="local_ip"
|
name="local_ip"
|
||||||
label={LL.AP_LOCAL_IP()}
|
label={LL.AP_LOCAL_IP()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -314,7 +314,7 @@ const NetworkSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="gateway_ip"
|
name="gateway_ip"
|
||||||
label={LL.NETWORK_GATEWAY()}
|
label={LL.NETWORK_GATEWAY()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -324,7 +324,7 @@ const NetworkSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="subnet_mask"
|
name="subnet_mask"
|
||||||
label={LL.NETWORK_SUBNET()}
|
label={LL.NETWORK_SUBNET()}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -334,7 +334,7 @@ const NetworkSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="dns_ip_1"
|
name="dns_ip_1"
|
||||||
label="DNS #1"
|
label="DNS #1"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -344,7 +344,7 @@ const NetworkSettings = () => {
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="dns_ip_2"
|
name="dns_ip_2"
|
||||||
label="DNS #2"
|
label="DNS #2"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -50,9 +50,7 @@ const WiFiNetworkScanner = () => {
|
|||||||
|
|
||||||
const renderNetworkScanner = () => {
|
const renderNetworkScanner = () => {
|
||||||
if (!networkList) {
|
if (!networkList) {
|
||||||
return (
|
return <FormLoader errorMessage={errorMessage || ''} />;
|
||||||
<FormLoader message={LL.SCANNING() + '...'} errorMessage={errorMessage} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return <WiFiNetworkSelector networkList={networkList} />;
|
return <WiFiNetworkSelector networkList={networkList} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const ManageUsers = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noAdminConfigured = () => !data.users.find((u) => u.admin);
|
const noAdminConfigured = () => !data.users.find((u) => u.admin);
|
||||||
@@ -260,15 +260,20 @@ const ManageUsers = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<GenerateToken username={generatingToken} onClose={closeGenerateToken} />
|
<GenerateToken
|
||||||
<User
|
username={generatingToken || ''}
|
||||||
user={user}
|
onClose={closeGenerateToken}
|
||||||
setUser={setUser}
|
|
||||||
creating={creating}
|
|
||||||
onDoneEditing={doneEditingUser}
|
|
||||||
onCancelEditing={cancelEditingUser}
|
|
||||||
validator={createUserValidator(data.users, creating)}
|
|
||||||
/>
|
/>
|
||||||
|
{user && (
|
||||||
|
<User
|
||||||
|
user={user}
|
||||||
|
setUser={setUser}
|
||||||
|
creating={creating}
|
||||||
|
onDoneEditing={doneEditingUser}
|
||||||
|
onCancelEditing={cancelEditingUser}
|
||||||
|
validator={createUserValidator(data.users, creating)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const Security = () => {
|
|||||||
],
|
],
|
||||||
useLocation()
|
useLocation()
|
||||||
);
|
);
|
||||||
const routerTab = matchedRoutes?.[0].route.path || false;
|
const routerTab = matchedRoutes?.[0]?.route.path || false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ const SecuritySettings = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateAndSubmit = async () => {
|
const validateAndSubmit = async () => {
|
||||||
@@ -69,7 +69,7 @@ const SecuritySettings = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="jwt_secret"
|
name="jwt_secret"
|
||||||
label={LL.SU_PASSWORD()}
|
label={LL.SU_PASSWORD()}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const User: FC<UserFormProps> = ({
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="username"
|
name="username"
|
||||||
label={LL.USERNAME(1)}
|
label={LL.USERNAME(1)}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -93,7 +93,7 @@ const User: FC<UserFormProps> = ({
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
<ValidatedPasswordField
|
<ValidatedPasswordField
|
||||||
fieldErrors={fieldErrors}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="password"
|
name="password"
|
||||||
label={LL.PASSWORD()}
|
label={LL.PASSWORD()}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const APStatus = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ const SystemActivity = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const showName = (id: number) => {
|
const showName = (id: number) => {
|
||||||
const name: keyof Translation['STATUS_NAMES'] = id;
|
const name: keyof Translation['STATUS_NAMES'] =
|
||||||
|
id.toString() as keyof Translation['STATUS_NAMES'];
|
||||||
return LL.STATUS_NAMES[name]();
|
return LL.STATUS_NAMES[name]();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ const SystemActivity = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const HardwareStatus = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ const MqttStatus = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderConnectionStatus = () => (
|
const renderConnectionStatus = () => (
|
||||||
|
|||||||
@@ -1,40 +1,27 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
|
|
||||||
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
|
||||||
import DnsIcon from '@mui/icons-material/Dns';
|
import DnsIcon from '@mui/icons-material/Dns';
|
||||||
import SwapVerticalCircleIcon from '@mui/icons-material/SwapVerticalCircle';
|
import SwapVerticalCircleIcon from '@mui/icons-material/SwapVerticalCircle';
|
||||||
import UpdateIcon from '@mui/icons-material/Update';
|
import UpdateIcon from '@mui/icons-material/Update';
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
DialogTitle,
|
|
||||||
Divider,
|
Divider,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemAvatar,
|
ListItemAvatar,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
TextField,
|
|
||||||
Typography,
|
|
||||||
useTheme
|
useTheme
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import type { Theme } from '@mui/material';
|
import type { Theme } from '@mui/material';
|
||||||
|
|
||||||
import * as NTPApi from 'api/ntp';
|
import * as NTPApi from 'api/ntp';
|
||||||
|
|
||||||
import { dialogStyle } from 'CustomTheme';
|
|
||||||
import { useRequest } from 'alova/client';
|
import { useRequest } from 'alova/client';
|
||||||
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
|
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { NTPStatusType, Time } from 'types';
|
import type { NTPStatusType } from 'types';
|
||||||
import { NTPSyncStatus } from 'types';
|
import { NTPSyncStatus } from 'types';
|
||||||
import { useInterval } from 'utils';
|
import { useInterval } from 'utils';
|
||||||
import { formatDateTime, formatLocalDateTime } from 'utils';
|
import { formatDateTime } from 'utils';
|
||||||
|
|
||||||
const NTPStatus = () => {
|
const NTPStatus = () => {
|
||||||
const { data, send: loadData, error } = useRequest(NTPApi.readNTPStatus);
|
const { data, send: loadData, error } = useRequest(NTPApi.readNTPStatus);
|
||||||
@@ -43,24 +30,11 @@ const NTPStatus = () => {
|
|||||||
void loadData();
|
void loadData();
|
||||||
});
|
});
|
||||||
|
|
||||||
const [localTime, setLocalTime] = useState<string>('');
|
|
||||||
const [settingTime, setSettingTime] = useState<boolean>(false);
|
|
||||||
const [processing, setProcessing] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle('NTP');
|
useLayoutTitle('NTP');
|
||||||
|
|
||||||
const { send: updateTime } = useRequest(
|
|
||||||
(local_time: Time) => NTPApi.updateTime(local_time),
|
|
||||||
{
|
|
||||||
immediate: false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
NTPApi.updateTime;
|
NTPApi.updateTime;
|
||||||
|
|
||||||
const isNtpActive = ({ status }: NTPStatusType) =>
|
|
||||||
status === NTPSyncStatus.NTP_ACTIVE;
|
|
||||||
const isNtpEnabled = ({ status }: NTPStatusType) =>
|
const isNtpEnabled = ({ status }: NTPStatusType) =>
|
||||||
status !== NTPSyncStatus.NTP_DISABLED;
|
status !== NTPSyncStatus.NTP_DISABLED;
|
||||||
|
|
||||||
@@ -77,14 +51,6 @@ const NTPStatus = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateLocalTime = (event: React.ChangeEvent<HTMLInputElement>) =>
|
|
||||||
setLocalTime(event.target.value);
|
|
||||||
|
|
||||||
const openSetTime = () => {
|
|
||||||
setLocalTime(formatLocalDateTime(new Date()));
|
|
||||||
setSettingTime(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const ntpStatus = ({ status }: NTPStatusType) => {
|
const ntpStatus = ({ status }: NTPStatusType) => {
|
||||||
@@ -100,73 +66,9 @@ const NTPStatus = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const configureTime = async () => {
|
|
||||||
setProcessing(true);
|
|
||||||
|
|
||||||
await updateTime({ local_time: formatLocalDateTime(new Date(localTime)) })
|
|
||||||
.then(async () => {
|
|
||||||
toast.success(LL.TIME_SET());
|
|
||||||
setSettingTime(false);
|
|
||||||
await loadData();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toast.error(LL.PROBLEM_UPDATING());
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setProcessing(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderSetTimeDialog = () => (
|
|
||||||
<Dialog
|
|
||||||
sx={dialogStyle}
|
|
||||||
open={settingTime}
|
|
||||||
onClose={() => setSettingTime(false)}
|
|
||||||
>
|
|
||||||
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
|
|
||||||
<DialogContent dividers>
|
|
||||||
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>
|
|
||||||
<Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography>
|
|
||||||
</Box>
|
|
||||||
<TextField
|
|
||||||
label={LL.LOCAL_TIME(0)}
|
|
||||||
type="datetime-local"
|
|
||||||
value={localTime}
|
|
||||||
onChange={updateLocalTime}
|
|
||||||
disabled={processing}
|
|
||||||
fullWidth
|
|
||||||
slotProps={{
|
|
||||||
inputLabel: {
|
|
||||||
shrink: true
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button
|
|
||||||
startIcon={<CancelIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setSettingTime(false)}
|
|
||||||
color="secondary"
|
|
||||||
>
|
|
||||||
{LL.CANCEL()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<AccessTimeIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={configureTime}
|
|
||||||
disabled={processing}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{LL.UPDATE()}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -219,23 +121,6 @@ const NTPStatus = () => {
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider variant="inset" component="li" />
|
<Divider variant="inset" component="li" />
|
||||||
</List>
|
</List>
|
||||||
<Box display="flex" flexWrap="wrap">
|
|
||||||
{data && !isNtpActive(data) && (
|
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
|
||||||
<ButtonRow>
|
|
||||||
<Button
|
|
||||||
onClick={openSetTime}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
startIcon={<AccessTimeIcon />}
|
|
||||||
>
|
|
||||||
{LL.SET_TIME(0)}
|
|
||||||
</Button>
|
|
||||||
</ButtonRow>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
{renderSetTimeDialog()}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ const NetworkStatus = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ const SystemStatus = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data || !LL) {
|
if (!data || !LL) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -31,13 +31,14 @@ import type { LogEntry, LogSettings } from 'types';
|
|||||||
import { LogLevel } from 'types';
|
import { LogLevel } from 'types';
|
||||||
import { updateValueDirty, useRest } from 'utils';
|
import { updateValueDirty, useRest } from 'utils';
|
||||||
|
|
||||||
const TextColors = {
|
const TextColors: Record<LogLevel, string> = {
|
||||||
[LogLevel.ERROR]: '#ff0000', // red
|
[LogLevel.ERROR]: '#ff0000', // red
|
||||||
[LogLevel.WARNING]: '#ff0000', // red
|
[LogLevel.WARNING]: '#ff0000', // red
|
||||||
[LogLevel.NOTICE]: '#ffffff', // white
|
[LogLevel.NOTICE]: '#ffffff', // white
|
||||||
[LogLevel.INFO]: '#ffcc00', // yellow
|
[LogLevel.INFO]: '#ffcc00', // yellow
|
||||||
[LogLevel.DEBUG]: '#00ffff', // cyan
|
[LogLevel.DEBUG]: '#00ffff', // cyan
|
||||||
[LogLevel.TRACE]: '#00ffff' // cyan
|
[LogLevel.TRACE]: '#00ffff', // cyan
|
||||||
|
[LogLevel.ALL]: '#ffffff' // white
|
||||||
};
|
};
|
||||||
|
|
||||||
const LogEntryLine = styled('span')(
|
const LogEntryLine = styled('span')(
|
||||||
@@ -109,7 +110,7 @@ const SystemLog = () => {
|
|||||||
origData,
|
origData,
|
||||||
dirtyFlags,
|
dirtyFlags,
|
||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
updateDataValue
|
updateDataValue as (value: unknown) => void
|
||||||
);
|
);
|
||||||
|
|
||||||
useSSE(fetchLogES, {
|
useSSE(fetchLogES, {
|
||||||
@@ -190,7 +191,7 @@ const SystemLog = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const SystemMonitor = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.onError((error) => {
|
.onError((error) => {
|
||||||
setErrorMessage(error.message);
|
setErrorMessage(String(error.error?.message || 'An error occurred'));
|
||||||
});
|
});
|
||||||
|
|
||||||
useInterval(() => {
|
useInterval(() => {
|
||||||
@@ -97,7 +97,7 @@ const SystemMonitor = () => {
|
|||||||
color="error"
|
color="error"
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
>
|
>
|
||||||
{LL.RESET(0)}
|
{LL.RESTART()}
|
||||||
</Button>
|
</Button>
|
||||||
</MessageBox>
|
</MessageBox>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { useContext, useEffect, useState } from 'react';
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import CheckIcon from '@mui/icons-material/Done';
|
import CheckIcon from '@mui/icons-material/Done';
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Grid2 as Grid,
|
Grid,
|
||||||
Link,
|
Link,
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
@@ -44,7 +44,10 @@ const Version = () => {
|
|||||||
const [restarting, setRestarting] = useState<boolean>(false);
|
const [restarting, setRestarting] = useState<boolean>(false);
|
||||||
const [openInstallDialog, setOpenInstallDialog] = useState<boolean>(false);
|
const [openInstallDialog, setOpenInstallDialog] = useState<boolean>(false);
|
||||||
const [usingDevVersion, setUsingDevVersion] = useState<boolean>(false);
|
const [usingDevVersion, setUsingDevVersion] = useState<boolean>(false);
|
||||||
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(false);
|
const [fetchDevVersion, setFetchDevVersion] = useState<boolean>(false);
|
||||||
|
const [devUpgradeAvailable, setDevUpgradeAvailable] = useState<boolean>(false);
|
||||||
|
const [stableUpgradeAvailable, setStableUpgradeAvailable] =
|
||||||
|
useState<boolean>(false);
|
||||||
const [internetLive, setInternetLive] = useState<boolean>(false);
|
const [internetLive, setInternetLive] = useState<boolean>(false);
|
||||||
const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
|
const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
|
||||||
|
|
||||||
@@ -62,8 +65,13 @@ const Version = () => {
|
|||||||
immediate: false
|
immediate: false
|
||||||
}
|
}
|
||||||
).onSuccess((event) => {
|
).onSuccess((event) => {
|
||||||
const data = event.data as { emsesp_version: string; upgradeable: boolean };
|
const data = event.data as {
|
||||||
setUpgradeAvailable(data.upgradeable);
|
emsesp_version: string;
|
||||||
|
dev_upgradeable: boolean;
|
||||||
|
stable_upgradeable: boolean;
|
||||||
|
};
|
||||||
|
setDevUpgradeAvailable(data.dev_upgradeable);
|
||||||
|
setStableUpgradeAvailable(data.stable_upgradeable);
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -71,7 +79,7 @@ const Version = () => {
|
|||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useRequest(SystemApi.readSystemStatus).onSuccess((event) => {
|
} = useRequest(SystemApi.readSystemStatus).onSuccess((event) => {
|
||||||
// older version of EMS-ESP on 4MB boards, can't use OTA because of SSL support in HttpClient
|
// older version of EMS-ESP using ESP32 (not S3) and no PSRAM, can't use OTA because of SSL support in HttpClient
|
||||||
if (event.data.arduino_version.startsWith('Tasmota')) {
|
if (event.data.arduino_version.startsWith('Tasmota')) {
|
||||||
setDownloadOnly(true);
|
setDownloadOnly(true);
|
||||||
}
|
}
|
||||||
@@ -102,7 +110,7 @@ const Version = () => {
|
|||||||
}, [latestVersion, latestDevVersion]);
|
}, [latestVersion, latestDevVersion]);
|
||||||
|
|
||||||
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
||||||
const DIVISIONS = [
|
const DIVISIONS: Array<{ amount: number; name: string }> = [
|
||||||
{ amount: 60, name: 'seconds' },
|
{ amount: 60, name: 'seconds' },
|
||||||
{ amount: 60, name: 'minutes' },
|
{ amount: 60, name: 'minutes' },
|
||||||
{ amount: 24, name: 'hours' },
|
{ amount: 24, name: 'hours' },
|
||||||
@@ -111,18 +119,21 @@ const Version = () => {
|
|||||||
{ amount: 12, name: 'months' },
|
{ amount: 12, name: 'months' },
|
||||||
{ amount: Number.POSITIVE_INFINITY, name: 'years' }
|
{ amount: Number.POSITIVE_INFINITY, name: 'years' }
|
||||||
];
|
];
|
||||||
function formatTimeAgo(date) {
|
function formatTimeAgo(date: Date) {
|
||||||
let duration = (date.getTime() - new Date().getTime()) / 1000;
|
let duration = (date.getTime() - new Date().getTime()) / 1000;
|
||||||
for (let i = 0; i < DIVISIONS.length; i++) {
|
for (let i = 0; i < DIVISIONS.length; i++) {
|
||||||
const division = DIVISIONS[i];
|
const division = DIVISIONS[i];
|
||||||
if (Math.abs(duration) < division.amount) {
|
if (division && Math.abs(duration) < division.amount) {
|
||||||
return rtf.format(
|
return rtf.format(
|
||||||
Math.round(duration),
|
Math.round(duration),
|
||||||
division.name as Intl.RelativeTimeFormatUnit
|
division.name as Intl.RelativeTimeFormatUnit
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
duration /= division.amount;
|
if (division) {
|
||||||
|
duration /= division.amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return rtf.format(0, 'seconds');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
|
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
|
||||||
@@ -138,20 +149,21 @@ const Version = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBinURL = () => {
|
const getBinURL = (showingDev: boolean) => {
|
||||||
if (!internetLive) {
|
if (!internetLive) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const filename =
|
const filename =
|
||||||
'EMS-ESP-' +
|
'EMS-ESP-' +
|
||||||
(usingDevVersion ? latestDevVersion.name : latestVersion.name).replaceAll(
|
(showingDev ? latestDevVersion.name : latestVersion.name).replaceAll(
|
||||||
'.',
|
'.',
|
||||||
'_'
|
'_'
|
||||||
) +
|
) +
|
||||||
'-' +
|
'-' +
|
||||||
getPlatform() +
|
getPlatform() +
|
||||||
'.bin';
|
'.bin';
|
||||||
return usingDevVersion
|
return showingDev
|
||||||
? DEV_URL + filename
|
? DEV_URL + filename
|
||||||
: STABLE_URL + 'v' + latestVersion.name + '/' + filename;
|
: STABLE_URL + 'v' + latestVersion.name + '/' + filename;
|
||||||
};
|
};
|
||||||
@@ -172,107 +184,127 @@ const Version = () => {
|
|||||||
|
|
||||||
useLayoutTitle('EMS-ESP Firmware');
|
useLayoutTitle('EMS-ESP Firmware');
|
||||||
|
|
||||||
const renderInstallDialog = () => (
|
const renderInstallDialog = () => {
|
||||||
<Dialog
|
const binURL = getBinURL(fetchDevVersion);
|
||||||
sx={dialogStyle}
|
|
||||||
open={openInstallDialog}
|
|
||||||
onClose={() => closeInstallDialog()}
|
|
||||||
>
|
|
||||||
<DialogTitle>
|
|
||||||
{LL.INSTALL() +
|
|
||||||
' ' +
|
|
||||||
(usingDevVersion ? LL.DEVELOPMENT() : LL.STABLE()) +
|
|
||||||
' Firmware'}
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogContent dividers>
|
|
||||||
<Typography mb={2}>
|
|
||||||
{LL.INSTALL_VERSION(
|
|
||||||
usingDevVersion ? latestDevVersion?.name : latestVersion?.name
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button
|
|
||||||
startIcon={<CancelIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => closeInstallDialog()}
|
|
||||||
color="secondary"
|
|
||||||
>
|
|
||||||
{LL.CANCEL()}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => closeInstallDialog()}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<Link underline="none" target="_blank" href={getBinURL()} color="primary">
|
|
||||||
{LL.DOWNLOAD(1)}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<WarningIcon color="warning" />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => installFirmwareURL(getBinURL())}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{LL.INSTALL()}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
|
|
||||||
const showFirmwareDialog = (useDevVersion?: boolean) => {
|
return (
|
||||||
setUsingDevVersion(useDevVersion || usingDevVersion);
|
<Dialog
|
||||||
|
sx={dialogStyle}
|
||||||
|
open={openInstallDialog}
|
||||||
|
onClose={() => closeInstallDialog()}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
{LL.UPDATE() +
|
||||||
|
' ' +
|
||||||
|
(fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()) +
|
||||||
|
' Firmware'}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent dividers>
|
||||||
|
<Typography mb={2}>
|
||||||
|
{LL.INSTALL_VERSION(
|
||||||
|
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
||||||
|
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
startIcon={<CancelIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => closeInstallDialog()}
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => closeInstallDialog()}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<Link underline="none" target="_blank" href={binURL} color="primary">
|
||||||
|
{LL.DOWNLOAD(0)}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
{!downloadOnly && (
|
||||||
|
<Button
|
||||||
|
startIcon={<WarningIcon color="warning" />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => installFirmwareURL(binURL)}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{LL.INSTALL()}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showFirmwareDialog = (useDevVersion: boolean) => {
|
||||||
|
setFetchDevVersion(useDevVersion);
|
||||||
setOpenInstallDialog(true);
|
setOpenInstallDialog(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeInstallDialog = () => {
|
const closeInstallDialog = () => {
|
||||||
setOpenInstallDialog(false);
|
setOpenInstallDialog(false);
|
||||||
setUsingDevVersion(data.emsesp_version.includes('dev'));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showButtons = (showDev?: boolean) => {
|
const showButtons = (showingDev: boolean) => {
|
||||||
if (!me.admin) {
|
const choice = showingDev
|
||||||
return;
|
? !usingDevVersion
|
||||||
|
? LL.SWITCH_RELEASE_TYPE(LL.DEVELOPMENT())
|
||||||
|
: devUpgradeAvailable
|
||||||
|
? LL.UPDATE_AVAILABLE()
|
||||||
|
: undefined
|
||||||
|
: usingDevVersion
|
||||||
|
? LL.SWITCH_RELEASE_TYPE(LL.STABLE())
|
||||||
|
: stableUpgradeAvailable
|
||||||
|
? LL.UPDATE_AVAILABLE()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!choice) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CheckIcon
|
||||||
|
color="success"
|
||||||
|
sx={{ verticalAlign: 'middle', ml: 0.5, mr: 0.5 }}
|
||||||
|
/>
|
||||||
|
<span style={{ color: '#66bb6a', fontSize: '0.8em' }}>
|
||||||
|
{LL.LATEST_VERSION(usingDevVersion ? LL.DEVELOPMENT() : LL.STABLE())}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
onClick={() => showFirmwareDialog(showingDev)}
|
||||||
|
>
|
||||||
|
{LL.REINSTALL()}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadOnly) {
|
if (!me.admin) {
|
||||||
return (
|
return;
|
||||||
<Button
|
|
||||||
sx={{ ml: 2 }}
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setOpenInstallDialog(false)}
|
|
||||||
color="warning"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<Link underline="none" target="_blank" href={getBinURL()} color="warning">
|
|
||||||
{LL.DOWNLOAD(1)}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
sx={{ ml: 2 }}
|
sx={{ ml: 2 }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="warning"
|
color={choice === LL.UPDATE_AVAILABLE() ? 'success' : 'warning'}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => showFirmwareDialog()}
|
onClick={() => showFirmwareDialog(showingDev)}
|
||||||
>
|
>
|
||||||
{upgradeAvailable || (!usingDevVersion && showDev)
|
{choice}
|
||||||
? LL.UPGRADE()
|
|
||||||
: LL.REINSTALL()}
|
|
||||||
…
|
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDev = data.emsesp_version.includes('dev');
|
const isDev = data.emsesp_version.includes('dev');
|
||||||
@@ -314,7 +346,25 @@ const Version = () => {
|
|||||||
<Typography>
|
<Typography>
|
||||||
{getPlatform()}
|
{getPlatform()}
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
({data.psram ? '+PSRAM' : '-PSRAM'})
|
(
|
||||||
|
{data.psram ? (
|
||||||
|
<CheckIcon
|
||||||
|
color="success"
|
||||||
|
sx={{
|
||||||
|
fontSize: '1.5em',
|
||||||
|
verticalAlign: 'middle'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CloseIcon
|
||||||
|
color="error"
|
||||||
|
sx={{
|
||||||
|
fontSize: '1.5em',
|
||||||
|
verticalAlign: 'middle'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
PSRAM)
|
||||||
</Typography>
|
</Typography>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -395,7 +445,7 @@ const Version = () => {
|
|||||||
{formatTimeAgo(new Date(latestVersion.published_at))})
|
{formatTimeAgo(new Date(latestVersion.published_at))})
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{!usingDevVersion && showButtons(false)}
|
{showButtons(false)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -417,24 +467,6 @@ const Version = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{upgradeAvailable ? (
|
|
||||||
<Typography mt={2} color="warning">
|
|
||||||
<InfoOutlinedIcon
|
|
||||||
color="warning"
|
|
||||||
sx={{ verticalAlign: 'middle', mr: 2 }}
|
|
||||||
/>
|
|
||||||
{LL.UPGRADE_AVAILABLE()}
|
|
||||||
</Typography>
|
|
||||||
) : (
|
|
||||||
<Typography mt={2} color="success">
|
|
||||||
<CheckIcon
|
|
||||||
color="success"
|
|
||||||
sx={{ verticalAlign: 'middle', mr: 2 }}
|
|
||||||
/>
|
|
||||||
{LL.LATEST_VERSION()}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Typography mt={2} color="warning">
|
<Typography mt={2} color="warning">
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import type { FC } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import type { BoxProps } from '@mui/material';
|
import type { BoxProps } from '@mui/material';
|
||||||
|
|
||||||
const ButtonRow: FC<BoxProps> = ({ children, ...rest }) => (
|
const ButtonRow = memo<BoxProps>(({ children, ...rest }) => (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
'& button, & a, & .MuiCard-root': {
|
'& button, & a, & .MuiCard-root': {
|
||||||
mt: 2,
|
mt: 2,
|
||||||
mx: 0.6,
|
mx: 0.6,
|
||||||
'&:last-child': {
|
'&:last-child': { mr: 0 },
|
||||||
mr: 0
|
'&:first-of-type': { ml: 0 }
|
||||||
},
|
|
||||||
'&:first-of-type': {
|
|
||||||
ml: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
));
|
||||||
|
|
||||||
|
ButtonRow.displayName = 'ButtonRow';
|
||||||
|
|
||||||
export default ButtonRow;
|
export default ButtonRow;
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Tooltip, type TooltipProps, styled, tooltipClasses } from '@mui/material';
|
import { Tooltip, type TooltipProps, styled, tooltipClasses } from '@mui/material';
|
||||||
|
|
||||||
export const ButtonTooltip = styled(({ className, ...props }: TooltipProps) => (
|
export const ButtonTooltip = styled(({ className, ...props }: TooltipProps) => (
|
||||||
<Tooltip {...props} placement="top" arrow classes={{ popper: className }} />
|
<Tooltip
|
||||||
|
{...props}
|
||||||
|
placement="top"
|
||||||
|
arrow
|
||||||
|
classes={{ ...(className && { popper: className }) }}
|
||||||
|
/>
|
||||||
))(({ theme }) => ({
|
))(({ theme }) => ({
|
||||||
[`& .${tooltipClasses.arrow}`]: {
|
[`& .${tooltipClasses.arrow}`]: {
|
||||||
color: theme.palette.success.main
|
color: theme.palette.success.main
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
|
// Optimized exports - use direct exports to reduce bundle size
|
||||||
|
export { default as SectionContent } from './SectionContent';
|
||||||
|
export { default as ButtonRow } from './ButtonRow';
|
||||||
|
export { default as MessageBox } from './MessageBox';
|
||||||
|
export { default as ButtonTooltip } from './ButtonTooltip';
|
||||||
|
|
||||||
|
// Re-export sub-modules
|
||||||
export * from './inputs';
|
export * from './inputs';
|
||||||
export * from './layout';
|
export * from './layout';
|
||||||
export * from './loading';
|
export * from './loading';
|
||||||
export * from './routing';
|
export * from './routing';
|
||||||
export * from './upload';
|
export * from './upload';
|
||||||
export { default as SectionContent } from './SectionContent';
|
|
||||||
export { default as ButtonRow } from './ButtonRow';
|
// Specific routing exports
|
||||||
export { default as MessageBox } from './MessageBox';
|
|
||||||
export { default as BlockNavigation } from './routing/BlockNavigation';
|
export { default as BlockNavigation } from './routing/BlockNavigation';
|
||||||
export { default as ButtonTooltip } from './ButtonTooltip';
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ const ValidatedTextField: FC<ValidatedTextFieldProps> = ({
|
|||||||
fieldErrors,
|
fieldErrors,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const errors = fieldErrors && fieldErrors[rest.name];
|
const errors = fieldErrors?.[rest.name];
|
||||||
const renderErrors = () =>
|
|
||||||
errors &&
|
|
||||||
errors.map((e) => <FormHelperText key={e.message}>{e.message}</FormHelperText>);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextField error={!!errors} {...rest} />
|
<TextField error={!!errors} {...rest} />
|
||||||
{renderErrors()}
|
{errors?.map((e) => (
|
||||||
|
<FormHelperText key={e.message}>{e.message}</FormHelperText>
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ const LayoutMenuItem = ({
|
|||||||
const selected = routeMatches(to, pathname);
|
const selected = routeMatches(to, pathname);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItemButton component={Link} to={to} disabled={disabled} selected={selected}>
|
<ListItemButton
|
||||||
|
component={Link}
|
||||||
|
to={to}
|
||||||
|
disabled={disabled || false}
|
||||||
|
selected={selected}
|
||||||
|
>
|
||||||
<ListItemIcon sx={{ color: selected ? '#90caf9' : '#9e9e9e' }}>
|
<ListItemIcon sx={{ color: selected ? '#90caf9' : '#9e9e9e' }}>
|
||||||
<Icon />
|
<Icon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -58,12 +58,22 @@ const LayoutMenuItem = ({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ListItemButton component={Link} to={to}>
|
<ListItemButton component={Link} to={to}>
|
||||||
<RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} />
|
<RenderIcon
|
||||||
|
icon={icon}
|
||||||
|
{...(bgcolor && { bgcolor })}
|
||||||
|
label={label}
|
||||||
|
text={text}
|
||||||
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
) : (
|
) : (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} />
|
<RenderIcon
|
||||||
|
icon={icon}
|
||||||
|
{...(bgcolor && { bgcolor })}
|
||||||
|
label={label}
|
||||||
|
text={text}
|
||||||
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
20
interface/src/components/loading/LazyLoader.tsx
Normal file
20
interface/src/components/loading/LazyLoader.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Box, CircularProgress } from '@mui/material';
|
||||||
|
|
||||||
|
const LazyLoader = () => (
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
minHeight="200px"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'background.default',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CircularProgress size={40} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default LazyLoader;
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export { default as LoadingSpinner } from './LoadingSpinner';
|
export { default as LoadingSpinner } from './LoadingSpinner';
|
||||||
export { default as FormLoader } from './FormLoader';
|
export { default as FormLoader } from './FormLoader';
|
||||||
|
export { default as LazyLoader } from './LazyLoader';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { Path } from 'react-router';
|
import type { Path } from 'react-router';
|
||||||
|
|
||||||
import type * as H from 'history';
|
|
||||||
import { jwtDecode } from 'jwt-decode';
|
import { jwtDecode } from 'jwt-decode';
|
||||||
import type { Me, SignInRequest, SignInResponse } from 'types';
|
import type { Me, SignInRequest, SignInResponse } from 'types';
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ export function getStorage() {
|
|||||||
return localStorage || sessionStorage;
|
return localStorage || sessionStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function storeLoginRedirect(location?: H.Location) {
|
export function storeLoginRedirect(location?: { pathname: string; search: string }) {
|
||||||
if (location) {
|
if (location) {
|
||||||
getStorage().setItem(SIGN_IN_PATHNAME, location.pathname);
|
getStorage().setItem(SIGN_IN_PATHNAME, location.pathname);
|
||||||
getStorage().setItem(SIGN_IN_SEARCH, location.search);
|
getStorage().setItem(SIGN_IN_SEARCH, location.search);
|
||||||
@@ -36,7 +35,7 @@ export function fetchLoginRedirect(): Partial<Path> {
|
|||||||
clearLoginRedirect();
|
clearLoginRedirect();
|
||||||
return {
|
return {
|
||||||
pathname: signInPathname || `/dashboard`,
|
pathname: signInPathname || `/dashboard`,
|
||||||
search: (signInPathname && signInSearch) || undefined
|
...(signInPathname && signInSearch && { search: signInSearch })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,59 @@
|
|||||||
// Code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
|
// Code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
|
||||||
import { type ChangeEvent, useRef, useState } from 'react';
|
import {
|
||||||
|
type ChangeEvent,
|
||||||
|
type DragEvent,
|
||||||
|
type MouseEvent,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
||||||
import UploadIcon from '@mui/icons-material/Upload';
|
import UploadIcon from '@mui/icons-material/Upload';
|
||||||
import { Box, Button } from '@mui/material';
|
import { Box, Button, Typography, styled } from '@mui/material';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
import './dragNdrop.css';
|
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
|
||||||
|
border: `2px dashed ${active ? '#6dc24b' : '#4282fe'}`,
|
||||||
|
backgroundColor: '#2e3339',
|
||||||
|
padding: theme.spacing(1.25),
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
position: 'relative',
|
||||||
|
borderRadius: theme.spacing(1),
|
||||||
|
cursor: 'pointer',
|
||||||
|
minHeight: '120px',
|
||||||
|
transition: 'border-color 0.2s ease-in-out'
|
||||||
|
}));
|
||||||
|
|
||||||
const DragNdrop = ({ text, onFileSelected }) => {
|
const UploadInfo = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
});
|
||||||
|
|
||||||
|
const FileInfo = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center'
|
||||||
|
});
|
||||||
|
|
||||||
|
const FileName = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: '14px',
|
||||||
|
color: '#6dc24b',
|
||||||
|
margin: theme.spacing(1, 0)
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface DragNdropProps {
|
||||||
|
text: string;
|
||||||
|
onFileSelected: (file: File) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
||||||
const [file, setFile] = useState<File>();
|
const [file, setFile] = useState<File>();
|
||||||
const [dragged, setDragged] = useState(false);
|
const [dragged, setDragged] = useState(false);
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
@@ -28,14 +71,17 @@ const DragNdrop = ({ text, onFileSelected }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (!e.target.files) {
|
if (!e.target.files || e.target.files.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkFileExtension(e.target.files[0]);
|
const selectedFile = e.target.files[0];
|
||||||
|
if (selectedFile) {
|
||||||
|
checkFileExtension(selectedFile);
|
||||||
|
}
|
||||||
e.target.value = ''; // this is to allow the same file to be selected again
|
e.target.value = ''; // this is to allow the same file to be selected again
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDrop = (event) => {
|
const handleDrop = (event: DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const droppedFiles = event.dataTransfer.files;
|
const droppedFiles = event.dataTransfer.files;
|
||||||
if (droppedFiles.length > 0) {
|
if (droppedFiles.length > 0) {
|
||||||
@@ -43,38 +89,40 @@ const DragNdrop = ({ text, onFileSelected }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFile = (event) => {
|
const handleRemoveFile = (event: MouseEvent<HTMLButtonElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
setFile(undefined);
|
setFile(undefined);
|
||||||
setDragged(false);
|
setDragged(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUploadClick = (event) => {
|
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onFileSelected(file);
|
if (file) {
|
||||||
|
onFileSelected(file);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBrowseClick = () => {
|
const handleBrowseClick = () => {
|
||||||
inputRef.current?.click();
|
inputRef.current?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragOver = (event) => {
|
const handleDragOver = (event: DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault(); // prevent file from being opened
|
event.preventDefault(); // prevent file from being opened
|
||||||
setDragged(true);
|
setDragged(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<DocumentUploader
|
||||||
className={`document-uploader ${file || dragged ? 'active' : ''}`}
|
active={!!(file || dragged)}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
onDragLeave={() => setDragged(false)}
|
onDragLeave={() => setDragged(false)}
|
||||||
onClick={handleBrowseClick}
|
onClick={handleBrowseClick}
|
||||||
>
|
>
|
||||||
<div className="upload-info">
|
<UploadInfo>
|
||||||
<CloudUploadIcon sx={{ marginRight: 4 }} color="primary" fontSize="large" />
|
<CloudUploadIcon sx={{ marginRight: 4 }} color="primary" fontSize="large" />
|
||||||
<p>{text}</p>
|
<Typography>{text}</Typography>
|
||||||
</div>
|
</UploadInfo>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
@@ -88,9 +136,9 @@ const DragNdrop = ({ text, onFileSelected }) => {
|
|||||||
|
|
||||||
{file && (
|
{file && (
|
||||||
<>
|
<>
|
||||||
<div className="file-info">
|
<FileInfo>
|
||||||
<p>{file.name}</p>
|
<FileName>{file.name}</FileName>
|
||||||
</div>
|
</FileInfo>
|
||||||
<Box>
|
<Box>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
@@ -112,7 +160,7 @@ const DragNdrop = ({ text, onFileSelected }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</DocumentUploader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,12 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import DragNdrop from './DragNdrop';
|
import DragNdrop from './DragNdrop';
|
||||||
import { LinearProgressWithLabel } from './LinearProgressWithLabel';
|
import { LinearProgressWithLabel } from './LinearProgressWithLabel';
|
||||||
|
|
||||||
const SingleUpload = ({ text, doRestart }) => {
|
interface SingleUploadProps {
|
||||||
|
text: string;
|
||||||
|
doRestart: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
||||||
const [md5, setMd5] = useState<string>();
|
const [md5, setMd5] = useState<string>();
|
||||||
const [file, setFile] = useState<File>();
|
const [file, setFile] = useState<File>();
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
@@ -25,8 +30,8 @@ const SingleUpload = ({ text, doRestart }) => {
|
|||||||
} = useRequest(SystemApi.uploadFile, {
|
} = useRequest(SystemApi.uploadFile, {
|
||||||
immediate: false
|
immediate: false
|
||||||
}).onSuccess(({ data }) => {
|
}).onSuccess(({ data }) => {
|
||||||
if (data) {
|
if (data && typeof data === 'object' && 'md5' in data) {
|
||||||
setMd5(data.md5 as string);
|
setMd5((data as { md5: string }).md5);
|
||||||
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
|
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
|
||||||
setFile(undefined);
|
setFile(undefined);
|
||||||
} else {
|
} else {
|
||||||
@@ -34,16 +39,19 @@ const SingleUpload = ({ text, doRestart }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(async () => {
|
useEffect(() => {
|
||||||
if (file) {
|
const uploadFile = async () => {
|
||||||
await sendUpload(file).catch((error: Error) => {
|
if (file) {
|
||||||
if (error.message === 'The user aborted a request') {
|
await sendUpload(file).catch((error: Error) => {
|
||||||
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
|
if (error.message.includes('The user aborted a request')) {
|
||||||
} else {
|
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
|
||||||
toast.warning('Invalid file extension or incompatible bin file');
|
} else {
|
||||||
}
|
toast.warning('Invalid file extension or incompatible bin file');
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void uploadFile();
|
||||||
}, [file]);
|
}, [file]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
.document-uploader {
|
|
||||||
border: 2px dashed #4282fe;
|
|
||||||
background-color: #2e3339;
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: #6dc24b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #6dc24b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -69,7 +69,12 @@ const Authentication: FC<RequiredChildrenProps> = ({ children }) => {
|
|||||||
|
|
||||||
// cache object to prevent re-renders
|
// cache object to prevent re-renders
|
||||||
const obj = useMemo(
|
const obj = useMemo(
|
||||||
() => ({ signIn, signOut, me, refresh }),
|
() => ({
|
||||||
|
signIn,
|
||||||
|
signOut,
|
||||||
|
refresh,
|
||||||
|
...(me && { me })
|
||||||
|
}),
|
||||||
[signIn, signOut, me, refresh]
|
[signIn, signOut, me, refresh]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ const cz: Translation = {
|
|||||||
UPLOAD: 'Nahrát',
|
UPLOAD: 'Nahrát',
|
||||||
DOWNLOAD: '{{S|s|s}}táhnout',
|
DOWNLOAD: '{{S|s|s}}táhnout',
|
||||||
INSTALL: 'Instalovat',
|
INSTALL: 'Instalovat',
|
||||||
|
REINSTALL: 'Znovu instalovat',
|
||||||
ABORTED: 'přerušeno',
|
ABORTED: 'přerušeno',
|
||||||
FAILED: 'neúspěšné',
|
FAILED: 'neúspěšné',
|
||||||
SUCCESSFUL: 'úspěšné',
|
SUCCESSFUL: 'úspěšné',
|
||||||
@@ -187,7 +188,7 @@ const cz: Translation = {
|
|||||||
COMPACT: 'Kompaktní',
|
COMPACT: 'Kompaktní',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace',
|
DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace',
|
||||||
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
|
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr',
|
||||||
ERROR: 'Neočekávaná chyba, zkuste to prosím znovu',
|
ERROR: 'Neočekávaná chyba, zkuste to prosím znovu',
|
||||||
TIME_SET: 'Čas nastaven',
|
TIME_SET: 'Čas nastaven',
|
||||||
MANAGE_USERS: 'Spravovat uživatele',
|
MANAGE_USERS: 'Spravovat uživatele',
|
||||||
@@ -331,28 +332,27 @@ const cz: Translation = {
|
|||||||
ALLVALUES: 'Všechny hodnoty',
|
ALLVALUES: 'Všechny hodnoty',
|
||||||
SPECIAL_FUNCTIONS: 'Speciální funkce',
|
SPECIAL_FUNCTIONS: 'Speciální funkce',
|
||||||
WAIT_FIRMWARE: 'Firmware se nahrává a instaluje',
|
WAIT_FIRMWARE: 'Firmware se nahrává a instaluje',
|
||||||
INSTALL_VERSION: 'Tímto se instalovat verze {0}. Jste si jistí?',
|
INSTALL_VERSION: 'Tímto se {0} verze {1}. Jste si jistí?',
|
||||||
UPGRADE_AVAILABLE: 'Je k dispozici aktualizace firmwaru!',
|
UPDATE_AVAILABLE: 'aktualizace dostupná',
|
||||||
LATEST_VERSION: 'Používáte nejnovější verzi firmwaru',
|
LATEST_VERSION: 'Používáte nejnovější verzi {0}firmwaru',
|
||||||
PLEASE_WAIT: 'Prosím čekejte',
|
PLEASE_WAIT: 'Prosím čekejte',
|
||||||
RESTARTING_PRE: 'Inicializace',
|
RESTARTING_PRE: 'Inicializace',
|
||||||
RESTARTING_POST: 'Příprava',
|
RESTARTING_POST: 'Příprava',
|
||||||
AUTO_SCROLL: 'Automatické rolování',
|
AUTO_SCROLL: 'Automatické rolování',
|
||||||
DASHBOARD: 'Dashboard',
|
DASHBOARD: 'Dashboard',
|
||||||
DEVELOPER_MODE: 'Režim vývojáře',
|
DEVELOPER_MODE: 'Režim vývojáře',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bajty',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bit Mask',
|
||||||
DUPLICATE: 'Duplikát',
|
DUPLICATE: 'Duplikát',
|
||||||
UPGRADE: 'Upgrade',
|
|
||||||
DASHBOARD_1: 'Všechny aktivní entity EMS jsou označené jako oblíbené. Všechny vlastní entity, harmonogramy a externí sensory jsou zobrazeny níže.',
|
DASHBOARD_1: 'Všechny aktivní entity EMS jsou označené jako oblíbené. Všechny vlastní entity, harmonogramy a externí sensory jsou zobrazeny níže.',
|
||||||
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte',
|
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
|
||||||
NO_DATA_2: 'modul sloužící k jejich výběru.',
|
NO_DATA_2: 'pro jejich výběr.',
|
||||||
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte',
|
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
|
||||||
THIS_VERSION: 'Tato verze',
|
THIS_VERSION: 'Tato verze',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Typ sestavení',
|
RELEASE_TYPE: 'Typ sestavení',
|
||||||
REINSTALL: 'Přeinstalovat',
|
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
|
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
|
||||||
|
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default cz;
|
export default cz;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const de: Translation = {
|
|||||||
CANCEL: 'Abbrechen',
|
CANCEL: 'Abbrechen',
|
||||||
RESET: 'Zurücksetzen',
|
RESET: 'Zurücksetzen',
|
||||||
APPLY_CHANGES: 'Änderungen anwenden ({0})',
|
APPLY_CHANGES: 'Änderungen anwenden ({0})',
|
||||||
UPDATE: 'Update',
|
UPDATE: 'Aktualisieren',
|
||||||
EXECUTE: 'Ausführen',
|
EXECUTE: 'Ausführen',
|
||||||
REMOVE: 'Entfernen',
|
REMOVE: 'Entfernen',
|
||||||
PROBLEM_UPDATING: 'Problem beim Aktualisieren',
|
PROBLEM_UPDATING: 'Problem beim Aktualisieren',
|
||||||
@@ -160,8 +160,9 @@ const de: Translation = {
|
|||||||
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 Systemdetails und hängen Sie sie an das Support-Issue an',
|
HELP_INFORMATION_4: 'Bitte laden Sie die Systemdetails und hängen Sie sie an das Support-Issue an',
|
||||||
UPLOAD: 'Hochladen',
|
UPLOAD: 'Hochladen',
|
||||||
DOWNLOAD: '{{H|h|h}}erunterladen',
|
DOWNLOAD: '{{Herunterladen|heruntergeladen|}}',
|
||||||
INSTALL: 'Installieren',
|
INSTALL: 'Installieren',
|
||||||
|
REINSTALL: 'Neu installieren',
|
||||||
ABORTED: 'abgebrochen',
|
ABORTED: 'abgebrochen',
|
||||||
FAILED: 'gescheitert',
|
FAILED: 'gescheitert',
|
||||||
SUCCESSFUL: 'erfolgreich',
|
SUCCESSFUL: 'erfolgreich',
|
||||||
@@ -331,9 +332,9 @@ const de: Translation = {
|
|||||||
ALLVALUES: 'Alle Werte',
|
ALLVALUES: 'Alle Werte',
|
||||||
SPECIAL_FUNCTIONS: 'Sonderfunktionen',
|
SPECIAL_FUNCTIONS: 'Sonderfunktionen',
|
||||||
WAIT_FIRMWARE: 'Die Firmware wird hochgeladen und installiert.',
|
WAIT_FIRMWARE: 'Die Firmware wird hochgeladen und installiert.',
|
||||||
INSTALL_VERSION: 'Dadurch wird die Version {0} heruntergeladen. Sind Sie sicher?',
|
INSTALL_VERSION: 'Dadurch wird die Version {1} {0}. Sind Sie sicher?',
|
||||||
UPGRADE_AVAILABLE: 'Es ist ein Firmware-Upgrade verfügbar.',
|
UPDATE_AVAILABLE: 'Firmware-Update verfügbar',
|
||||||
LATEST_VERSION: 'Sie verwenden die neueste Firmware-Version',
|
LATEST_VERSION: 'Sie verwenden die neueste {0} Firmware-Version',
|
||||||
PLEASE_WAIT: 'Bitte warten',
|
PLEASE_WAIT: 'Bitte warten',
|
||||||
RESTARTING_PRE: 'Initialisierung',
|
RESTARTING_PRE: 'Initialisierung',
|
||||||
RESTARTING_POST: 'Vorbereitung',
|
RESTARTING_POST: 'Vorbereitung',
|
||||||
@@ -343,7 +344,6 @@ const de: Translation = {
|
|||||||
BYTES: 'Bytes',
|
BYTES: 'Bytes',
|
||||||
BITMASK: 'Bit Maske',
|
BITMASK: 'Bit Maske',
|
||||||
DUPLICATE: 'Kopieren',
|
DUPLICATE: 'Kopieren',
|
||||||
UPGRADE: 'Aktualisieren',
|
|
||||||
DASHBOARD_1: 'Alle EMS-Entitäten, die aktiv und als Favorit markiert sind, sowie alle benutzerdefinierten Entitäten, Zeitpläne und externen Sensordaten werden unten angezeigt.',
|
DASHBOARD_1: 'Alle EMS-Entitäten, die aktiv und als Favorit markiert sind, sowie alle benutzerdefinierten Entitäten, Zeitpläne und externen Sensordaten werden unten angezeigt.',
|
||||||
NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul',
|
NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul',
|
||||||
NO_DATA_2: ', um sie zu markieren.',
|
NO_DATA_2: ', um sie zu markieren.',
|
||||||
@@ -351,8 +351,8 @@ const de: Translation = {
|
|||||||
THIS_VERSION: 'Diese Version',
|
THIS_VERSION: 'Diese Version',
|
||||||
PLATFORM: 'Plattform',
|
PLATFORM: 'Plattform',
|
||||||
RELEASE_TYPE: 'Release Typ',
|
RELEASE_TYPE: 'Release Typ',
|
||||||
REINSTALL: 'Neu installieren',
|
INTERNET_CONNECTION_REQUIRED: 'Für die automatische Versionsprüfung und Aktualisierung ist eine Internetverbindung erforderlich',
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internetverbindung erforderlich für automatische Version-Überprüfung und -Aktualisierung',
|
SWITCH_RELEASE_TYPE: 'Zum {0}-Release wechseln'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ const en: Translation = {
|
|||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
INSTALL: 'Install',
|
INSTALL: 'Install',
|
||||||
|
REINSTALL: 'Reinstall',
|
||||||
ABORTED: 'aborted',
|
ABORTED: 'aborted',
|
||||||
FAILED: 'failed',
|
FAILED: 'failed',
|
||||||
SUCCESSFUL: 'successful',
|
SUCCESSFUL: 'successful',
|
||||||
@@ -331,9 +332,9 @@ const en: Translation = {
|
|||||||
ALLVALUES: 'All Values',
|
ALLVALUES: 'All Values',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions',
|
SPECIAL_FUNCTIONS: 'Special Functions',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing',
|
WAIT_FIRMWARE: 'Firmware is uploading and installing',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?',
|
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!',
|
UPDATE_AVAILABLE: 'update available',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version',
|
LATEST_VERSION: 'You are using the latest {0} firmware version',
|
||||||
PLEASE_WAIT: 'Please wait',
|
PLEASE_WAIT: 'Please wait',
|
||||||
RESTARTING_PRE: 'Initializing',
|
RESTARTING_PRE: 'Initializing',
|
||||||
RESTARTING_POST: 'Preparing',
|
RESTARTING_POST: 'Preparing',
|
||||||
@@ -344,15 +345,14 @@ const en: Translation = {
|
|||||||
BYTES: 'Bytes',
|
BYTES: 'Bytes',
|
||||||
BITMASK: 'Bit Mask',
|
BITMASK: 'Bit Mask',
|
||||||
DUPLICATE: 'Duplicate',
|
DUPLICATE: 'Duplicate',
|
||||||
UPGRADE: 'Upgrade',
|
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the',
|
NO_DATA_1: 'No favorite EMS entities found yet. Use the',
|
||||||
NO_DATA_2: 'module to mark them.',
|
NO_DATA_2: 'module to mark them.',
|
||||||
NO_DATA_3: 'To see all available entities go to',
|
NO_DATA_3: 'To see all available entities go to',
|
||||||
THIS_VERSION: 'This Version',
|
THIS_VERSION: 'This Version',
|
||||||
PLATFORM: 'Platform',
|
PLATFORM: 'Platform',
|
||||||
RELEASE_TYPE: 'Release Type',
|
RELEASE_TYPE: 'Release Type',
|
||||||
REINSTALL: 'Re-install',
|
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
|
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
|
||||||
|
SWITCH_RELEASE_TYPE: 'Switch to {0} release'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ const fr: Translation = {
|
|||||||
CHANGE_VALUE: 'Changer la valeur',
|
CHANGE_VALUE: 'Changer la valeur',
|
||||||
CANCEL: 'Annuler',
|
CANCEL: 'Annuler',
|
||||||
RESET: 'Réinitialiser',
|
RESET: 'Réinitialiser',
|
||||||
APPLY_CHANGES: 'Apply Changes ({0})', // TODO translate
|
APPLY_CHANGES: 'Appliquer les changements ({0})',
|
||||||
UPDATE: 'Update', // TODO translate
|
UPDATE: 'Update',
|
||||||
EXECUTE: 'Execute', // TODO translate
|
EXECUTE: 'Execute',
|
||||||
REMOVE: 'Enlever',
|
REMOVE: 'Enlever',
|
||||||
PROBLEM_UPDATING: 'Problème lors de la mise à jour',
|
PROBLEM_UPDATING: 'Problème lors de la mise à jour',
|
||||||
PROBLEM_LOADING: 'Problème lors du chargement',
|
PROBLEM_LOADING: 'Problème lors du chargement',
|
||||||
@@ -66,13 +66,13 @@ const fr: Translation = {
|
|||||||
TEMP_SENSOR: 'Capteur de température',
|
TEMP_SENSOR: 'Capteur de température',
|
||||||
TEMP_SENSORS: 'Capteurs de température',
|
TEMP_SENSORS: 'Capteurs de température',
|
||||||
WRITE_CMD_SENT: 'Envoyer la commande sent',
|
WRITE_CMD_SENT: 'Envoyer la commande sent',
|
||||||
EMS_BUS_WARNING: 'Bus EMS déconnecté. Si ce message persiste après quelques secondes, vérifiez les paramètres et la configuration de la carte.',
|
EMS_BUS_WARNING: 'Bus EMS déconnecté. Si ce message persiste après quelques secondes, vérifiez les paramètres et la configuration de la carte.',
|
||||||
EMS_BUS_SCANNING: 'Scan des appareils EMS...',
|
EMS_BUS_SCANNING: 'Scan des appareils EMS...',
|
||||||
CONNECTED: 'Connecté',
|
CONNECTED: 'Connecté',
|
||||||
TX_ISSUES: 'Problèmes de transmission (Tx) - Essayez un autre mode Tx',
|
TX_ISSUES: 'Problèmes de transmission (Tx) - Essayez un autre mode Tx',
|
||||||
DISCONNECTED: 'Déconnecté',
|
DISCONNECTED: 'Déconnecté',
|
||||||
EMS_SCAN: 'Etes-vous sûr de vouloir lancer un scan complet du bus EMS ?',
|
EMS_SCAN: 'Etes-vous sûr de vouloir lancer un scan complet du bus EMS ?',
|
||||||
DATA_TRAFFIC: 'Data Traffic', // TODO translate
|
DATA_TRAFFIC: 'Traffic des données',
|
||||||
EMS_DEVICE: 'Appareils EMS',
|
EMS_DEVICE: 'Appareils EMS',
|
||||||
SUCCESS: 'SUCCÈS',
|
SUCCESS: 'SUCCÈS',
|
||||||
FAIL: 'ÉCHEC',
|
FAIL: 'ÉCHEC',
|
||||||
@@ -114,9 +114,9 @@ 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
|
HEATINGOFF: 'Démarrer le chauffage avec le chauffage forcé éteint',
|
||||||
REMOTE_TIMEOUT: 'Remote timeout',
|
REMOTE_TIMEOUT: 'Remote timeout',
|
||||||
REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate
|
REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature',
|
||||||
MIN_DURATION: 'Wait time',
|
MIN_DURATION: 'Wait time',
|
||||||
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',
|
||||||
@@ -148,7 +148,7 @@ const fr: Translation = {
|
|||||||
CUSTOMIZATIONS_HELP_3: "désactiver l'action d'écriture",
|
CUSTOMIZATIONS_HELP_3: "désactiver l'action d'écriture",
|
||||||
CUSTOMIZATIONS_HELP_4: "exclure de MQTT et de l'API",
|
CUSTOMIZATIONS_HELP_4: "exclure de MQTT et de l'API",
|
||||||
CUSTOMIZATIONS_HELP_5: 'cacher des appareils',
|
CUSTOMIZATIONS_HELP_5: 'cacher des appareils',
|
||||||
CUSTOMIZATIONS_HELP_6: 'remove from memory', // TODO translate
|
CUSTOMIZATIONS_HELP_6: 'supprimer de la mémoire',
|
||||||
SELECT_DEVICE: 'Sélectionnez un appareil',
|
SELECT_DEVICE: 'Sélectionnez un appareil',
|
||||||
SET_ALL: 'tout régler',
|
SET_ALL: 'tout régler',
|
||||||
OPTIONS: 'Options',
|
OPTIONS: 'Options',
|
||||||
@@ -162,20 +162,21 @@ const fr: Translation = {
|
|||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
INSTALL: 'Installer',
|
INSTALL: 'Installer',
|
||||||
|
REINSTALL: 'Réinstaller',
|
||||||
ABORTED: 'annulé',
|
ABORTED: 'annulé',
|
||||||
FAILED: 'échoué',
|
FAILED: 'échoué',
|
||||||
SUCCESSFUL: 'réussi',
|
SUCCESSFUL: 'réussi',
|
||||||
SYSTEM: 'Système',
|
SYSTEM: 'Système',
|
||||||
LOG_OF: '{0} Log',
|
LOG_OF: '{0} Log',
|
||||||
STATUS_OF: 'Statut {0}',
|
STATUS_OF: 'Statut {0}',
|
||||||
DOWNLOAD_UPLOAD: 'Download/Upload', // TODO translate
|
DOWNLOAD_UPLOAD: 'Télécharger/Mettre à jour',
|
||||||
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 ?",
|
||||||
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
|
AVAILABLE_VERSION: 'Versions disponibles',
|
||||||
STABLE: 'Stable', // TODO translate
|
STABLE: 'Stable',
|
||||||
DEVELOPMENT: 'Développement',
|
DEVELOPMENT: 'Développement',
|
||||||
UPTIME: 'Durée de fonctionnement du système',
|
UPTIME: 'Durée de fonctionnement du système',
|
||||||
FREE_MEMORY: 'Libre Memory',
|
FREE_MEMORY: 'Libre Memory',
|
||||||
@@ -185,9 +186,9 @@ const fr: Translation = {
|
|||||||
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',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
|
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
|
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||||
ERROR: 'Erreur inattendue, veuillez réessayer',
|
ERROR: 'Erreur inattendue, veuillez réessayer',
|
||||||
TIME_SET: 'Time set',
|
TIME_SET: 'Time set',
|
||||||
MANAGE_USERS: 'Gérer les utilisateurs',
|
MANAGE_USERS: 'Gérer les utilisateurs',
|
||||||
@@ -217,7 +218,7 @@ const fr: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_2: 'Publier vers des topics de commande (ioBroker)',
|
MQTT_PUBLISH_TEXT_2: 'Publier vers des topics de commande (ioBroker)',
|
||||||
MQTT_PUBLISH_TEXT_3: 'Activer la découverte MQTT',
|
MQTT_PUBLISH_TEXT_3: 'Activer la découverte MQTT',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Préfixe pour les topics découverte',
|
MQTT_PUBLISH_TEXT_4: 'Préfixe pour les topics découverte',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type', // TODO translate
|
MQTT_PUBLISH_TEXT_5: 'Type de découverte',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Intervalles de publication',
|
MQTT_PUBLISH_INTERVALS: 'Intervalles de publication',
|
||||||
MQTT_INT_BOILER: 'Chaudières et pompes à chaleur',
|
MQTT_INT_BOILER: 'Chaudières et pompes à chaleur',
|
||||||
MQTT_INT_THERMOSTATS: 'Thermostats',
|
MQTT_INT_THERMOSTATS: 'Thermostats',
|
||||||
@@ -226,10 +227,10 @@ const fr: Translation = {
|
|||||||
MQTT_INT_WATER: 'Modules eau',
|
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: 'Format de l\'ID de l\'entité',
|
||||||
MQTT_ENTITY_FORMAT_0: 'Single instance, long name (v3.4)', // TODO translate
|
MQTT_ENTITY_FORMAT_0: 'Instance unique, nom long (v3.4)',
|
||||||
MQTT_ENTITY_FORMAT_1: 'Single instance, short name', // TODO translate
|
MQTT_ENTITY_FORMAT_1: 'Instance unique, nom court',
|
||||||
MQTT_ENTITY_FORMAT_2: 'Multiple instances, short name', // TODO translate
|
MQTT_ENTITY_FORMAT_2: 'Instances multiples, nom court',
|
||||||
MQTT_CLEAN_SESSION: 'Flag Clean Session',
|
MQTT_CLEAN_SESSION: 'Flag Clean Session',
|
||||||
MQTT_RETAIN_FLAG: 'Toujours activer le Retain Flag',
|
MQTT_RETAIN_FLAG: 'Toujours activer le Retain Flag',
|
||||||
INACTIVE: 'Inactif',
|
INACTIVE: 'Inactif',
|
||||||
@@ -260,7 +261,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',
|
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
NETWORK_BLANK_BSSID: 'laisser vide pour utiliser uniquement le SSID',
|
||||||
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',
|
||||||
@@ -280,79 +281,78 @@ const fr: Translation = {
|
|||||||
ENTITY: 'entité',
|
ENTITY: 'entité',
|
||||||
MIN: 'min',
|
MIN: 'min',
|
||||||
MAX: 'max',
|
MAX: 'max',
|
||||||
BLOCK_NAVIGATE_1: 'You have unsaved changes', // TODO translate
|
BLOCK_NAVIGATE_1: 'Vous avez des modifications non enregistrées',
|
||||||
BLOCK_NAVIGATE_2: 'If you navigate to a different page, your unsaved changes will be lost. Are you sure you want to leave this page?', // TODO translate
|
BLOCK_NAVIGATE_2: 'Si vous naviguez vers une autre page, vos modifications non enregistrées seront perdues. Êtes-vous sûr de vouloir quitter cette page ?',
|
||||||
STAY: 'Stay', // TODO translate
|
STAY: 'Rester',
|
||||||
LEAVE: 'Leave', // TODO translate
|
LEAVE: 'Quitter',
|
||||||
SCHEDULER: 'Scheduler', // TODO translate
|
SCHEDULER: 'Scheduler',
|
||||||
SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT', // TODO translate
|
SCHEDULER_HELP_1: 'Automatiser les commandes en ajoutant des événements programmés ci-dessous. Définissez un nom unique pour activer/désactiver l\'activation via API/MQTT',
|
||||||
SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
|
SCHEDULER_HELP_2: 'Utiliser 00:00 pour déclencher une fois au démarrage',
|
||||||
SCHEDULE: 'Schedule', // TODO translate
|
SCHEDULE: 'Programme',
|
||||||
TIME: 'Time', // TODO translate
|
TIME: 'Temps',
|
||||||
TIMER: 'Timer', // TODO translate
|
TIMER: 'Minuteur',
|
||||||
ONCHANGE: 'Sur le changement', // TODO translate
|
ONCHANGE: 'Sur le changement',
|
||||||
CONDITION: 'Condition', // TODO translate
|
CONDITION: 'Condition',
|
||||||
IMMEDIATE: 'Immédiate', // TODO translate
|
IMMEDIATE: 'Immédiat',
|
||||||
SCHEDULE_UPDATED: 'Schedule updated', // TODO translate
|
SCHEDULE_UPDATED: 'Programme mis à jour',
|
||||||
SCHEDULE_TIMER_1: 'on startup', // TODO translate
|
SCHEDULE_TIMER_1: 'au démarrage',
|
||||||
SCHEDULE_TIMER_2: 'every minute', // TODO translate
|
SCHEDULE_TIMER_2: 'toutes les minutes',
|
||||||
SCHEDULE_TIMER_3: 'every hour', // TODO translate
|
SCHEDULE_TIMER_3: 'toutes les heures',
|
||||||
CUSTOM_ENTITIES: 'Custom Entities', // TODO translate
|
CUSTOM_ENTITIES: 'Entités personnalisées',
|
||||||
ENTITIES_HELP_1: 'Fetch custom entities from the EMS bus', // TODO translate
|
ENTITIES_HELP_1: 'Récupérer les entités personnalisées du bus EMS',
|
||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entités mises à jour',
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Écriture',
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Affichage',
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Rechercher',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'Certificat racine TLS (laisser vide pour l\'insecurité)',
|
||||||
ENABLE_TLS: 'Activer TLS',
|
ENABLE_TLS: 'Activer TLS',
|
||||||
ON: 'On', // TODO translate
|
ON: 'On',
|
||||||
OFF: 'Off', // TODO translate
|
OFF: 'Off',
|
||||||
POLARITY: 'Polarity', // TODO translate
|
POLARITY: 'Polarity',
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
ACTIVEHIGH: 'Actif haut',
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
ACTIVELOW: 'Actif bas',
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
UNCHANGED: 'Inchangé',
|
||||||
ALWAYS: 'Always', // TODO translate
|
ALWAYS: 'Toujours',
|
||||||
ACTIVITY: 'Activity', // TODO translate
|
ACTIVITY: 'Activité',
|
||||||
CONFIGURE: 'Configure {0}', // TODO translate
|
CONFIGURE: 'Configurer {0}',
|
||||||
SYSTEM_MEMORY: 'System Memory', // TODO translate
|
SYSTEM_MEMORY: 'Mémoire système',
|
||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modifier les paramètres de l\'application EMS-ESP',
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Ajouter ou supprimer des utilisateurs',
|
||||||
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware', // TODO translate
|
DOWNLOAD_UPLOAD_1: 'Télécharger et mettre à jour les paramètres et le firmware',
|
||||||
MODULES: 'Module', // TODO translate
|
MODULES: 'Module',
|
||||||
MODULES_1: 'Activer ou désactiver les modules externes',
|
MODULES_1: 'Activer ou désactiver les modules externes',
|
||||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
MODULES_UPDATED: 'Modules mis à jour',
|
||||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
MODULES_DESCRIPTION: 'Cliquer sur le module pour activer ou désactiver les modules EMS-ESP',
|
||||||
MODULES_NONE: 'No external modules detected', // TODO translate
|
MODULES_NONE: 'Aucun module externe détecté',
|
||||||
RENAME: 'Rename', // TODO translate
|
RENAME: 'Renommer',
|
||||||
ENABLE_MODBUS: 'Activer Modbus',
|
ENABLE_MODBUS: 'Activer Modbus',
|
||||||
VIEW_LOG: 'View log to diagnose issues', // TODO translate
|
VIEW_LOG: 'Voir le journal pour diagnostiquer les problèmes',
|
||||||
UPLOAD_DRAG: 'drag and drop a file here or click to select one', // TODO translate
|
UPLOAD_DRAG: 'glisser-déposer un fichier ici ou cliquer pour en sélectionner un',
|
||||||
SERVICES: 'Services', // TODO translate
|
SERVICES: 'Services',
|
||||||
ALLVALUES: 'All Values', // TODO translate
|
ALLVALUES: 'Toutes les valeurs',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions',
|
SPECIAL_FUNCTIONS: 'Fonctions spéciales',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
WAIT_FIRMWARE: 'Firmware en cours de téléchargement et d\'installation',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
INSTALL_VERSION: 'Cela va {0} la version {1}. Êtes-vous sûr ?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
UPDATE_AVAILABLE: 'mise à jour disponible',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version', // TODO translate
|
LATEST_VERSION: 'Vous utilisez la dernière version {0} du firmware',
|
||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Veuillez patienter',
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initialisation',
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Préparation',
|
||||||
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
AUTO_SCROLL: 'Défilement automatique',
|
||||||
DASHBOARD: 'Dashboard', // TODO translate
|
DASHBOARD: 'Tableau de bord',
|
||||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
DEVELOPER_MODE: 'Mode développeur',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Octets',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Masque de bits',
|
||||||
DUPLICATE: 'Duplicate', // TODO translate
|
DUPLICATE: 'Dupliquer',
|
||||||
UPGRADE: 'Upgrade', // TODO translate
|
DASHBOARD_1: 'Toutes les entités EMS actives et marquées comme favoris, plus toutes les entités personnalisées, les programmes et les données des capteurs externes sont affichées ci-dessous.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'module pour les marquer.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Cette version',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Plateforme',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Type de version',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
INTERNET_CONNECTION_REQUIRED: 'Connexion Internet requise pour la vérification automatique des versions et la mise à niveau',
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
SWITCH_RELEASE_TYPE: 'Passer à la version {0}'
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const it: Translation = {
|
|||||||
TX_ISSUES: 'Problema di Tx - prova una modalità differente',
|
TX_ISSUES: 'Problema di Tx - prova una modalità differente',
|
||||||
DISCONNECTED: 'Disconnesso',
|
DISCONNECTED: 'Disconnesso',
|
||||||
EMS_SCAN: 'Sei sicuro di voler iniziare una scansione completa del bus EMS ?',
|
EMS_SCAN: 'Sei sicuro di voler iniziare una scansione completa del bus EMS ?',
|
||||||
DATA_TRAFFIC: 'Data Traffic', // TODO translate
|
DATA_TRAFFIC: 'Traffico dati',
|
||||||
EMS_DEVICE: 'Dispositivo EMS ',
|
EMS_DEVICE: 'Dispositivo EMS ',
|
||||||
SUCCESS: 'SUCCESSO',
|
SUCCESS: 'SUCCESSO',
|
||||||
FAIL: 'FALLITO',
|
FAIL: 'FALLITO',
|
||||||
@@ -115,7 +115,7 @@ const it: Translation = {
|
|||||||
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',
|
||||||
REMOTE_TIMEOUT: 'Remote timeout',
|
REMOTE_TIMEOUT: 'Remote timeout',
|
||||||
REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate
|
REMOTE_TIMEOUT_EN: 'Disabilitare il telecomando in caso di temperatura ambiente mancante',
|
||||||
HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento',
|
HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento',
|
||||||
MIN_DURATION: 'Wait time',
|
MIN_DURATION: 'Wait time',
|
||||||
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
ENABLE_SHOWER_TIMER: 'Abilita timer doccia',
|
||||||
@@ -162,6 +162,7 @@ const it: Translation = {
|
|||||||
UPLOAD: 'Carica',
|
UPLOAD: 'Carica',
|
||||||
DOWNLOAD: 'Scarica',
|
DOWNLOAD: 'Scarica',
|
||||||
INSTALL: 'Installare {0}',
|
INSTALL: 'Installare {0}',
|
||||||
|
REINSTALL: 'Riavviare',
|
||||||
ABORTED: 'Annullato',
|
ABORTED: 'Annullato',
|
||||||
FAILED: 'Fallito',
|
FAILED: 'Fallito',
|
||||||
SUCCESSFUL: 'Riuscito',
|
SUCCESSFUL: 'Riuscito',
|
||||||
@@ -174,8 +175,8 @@ const it: Translation = {
|
|||||||
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??',
|
||||||
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
|
AVAILABLE_VERSION: 'Versioni disponibili',
|
||||||
STABLE: 'Stable', // TODO translate
|
STABLE: 'Stabile',
|
||||||
DEVELOPMENT: 'Sviluppo',
|
DEVELOPMENT: 'Sviluppo',
|
||||||
UPTIME: 'Tempo di attività del sistema',
|
UPTIME: 'Tempo di attività del sistema',
|
||||||
FREE_MEMORY: 'Free Memory',
|
FREE_MEMORY: 'Free Memory',
|
||||||
@@ -184,10 +185,10 @@ const it: Translation = {
|
|||||||
APPSIZE: 'Applicazione (Partizione: 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: 'Compatto',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
|
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
|
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||||
ERROR: 'Errore Inaspettato, prego tenta ancora',
|
ERROR: 'Errore Inaspettato, prego tenta ancora',
|
||||||
TIME_SET: 'Imposta Ora',
|
TIME_SET: 'Imposta Ora',
|
||||||
MANAGE_USERS: 'Gestione Utenti',
|
MANAGE_USERS: 'Gestione Utenti',
|
||||||
@@ -260,7 +261,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
|
NETWORK_BLANK_BSSID: 'lasciare vuoto per usare solo SSID',
|
||||||
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',
|
||||||
@@ -303,56 +304,55 @@ const it: Translation = {
|
|||||||
WRITEABLE: 'Scrivibile',
|
WRITEABLE: 'Scrivibile',
|
||||||
SHOWING: 'Visualizza',
|
SHOWING: 'Visualizza',
|
||||||
SEARCH: 'Ricerca',
|
SEARCH: 'Ricerca',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'Certificato radice TLS (lasciare vuoto per l\'insecure)',
|
||||||
ENABLE_TLS: 'Abilita TLS',
|
ENABLE_TLS: 'Abilita TLS',
|
||||||
ON: 'On', // TODO translate
|
ON: 'On',
|
||||||
OFF: 'Off', // TODO translate
|
OFF: 'Off',
|
||||||
POLARITY: 'Polarity', // TODO translate
|
POLARITY: 'Polarity',
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
ACTIVEHIGH: 'Active High',
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
ACTIVELOW: 'Active Low',
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
UNCHANGED: 'Unchanged',
|
||||||
ALWAYS: 'Always', // TODO translate
|
ALWAYS: 'Always',
|
||||||
ACTIVITY: 'Activity', // TODO translate
|
ACTIVITY: 'Activity',
|
||||||
CONFIGURE: 'Configure {0}', // TODO translate
|
CONFIGURE: 'Configure {0}',
|
||||||
SYSTEM_MEMORY: 'System Memory', // TODO translate
|
SYSTEM_MEMORY: 'System Memory',
|
||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users',
|
||||||
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware', // TODO translate
|
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware',
|
||||||
MODULES: 'Module', // TODO translate
|
MODULES: 'Module',
|
||||||
MODULES_1: 'Attiva o disattiva i moduli esterni', // TODO translate
|
MODULES_1: 'Attiva o disattiva i moduli esterni',
|
||||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
MODULES_UPDATED: 'Modules updated',
|
||||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules',
|
||||||
MODULES_NONE: 'No external modules detected', // TODO translate
|
MODULES_NONE: 'No external modules detected',
|
||||||
RENAME: 'Rename', // TODO translate
|
RENAME: 'Rename',
|
||||||
ENABLE_MODBUS: 'Abilita Modbus',
|
ENABLE_MODBUS: 'Abilita Modbus',
|
||||||
VIEW_LOG: 'View log to diagnose issues', // TODO translate
|
VIEW_LOG: 'Visualizza log per diagnosticare problemi',
|
||||||
UPLOAD_DRAG: 'drag and drop a file here or click to select one', // TODO translate
|
UPLOAD_DRAG: 'trascina e rilascia un file qui o clicca per selezionare uno',
|
||||||
SERVICES: 'Services', // TODO translate
|
SERVICES: 'Servizi',
|
||||||
ALLVALUES: 'All Values', // TODO translate
|
ALLVALUES: 'Tutti i valori',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
SPECIAL_FUNCTIONS: 'Funzioni speciali',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
WAIT_FIRMWARE: 'Firmware è in upload e installazione',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
INSTALL_VERSION: 'Questo installerà la versione {1} {0}. Sei sicuro?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
UPDATE_AVAILABLE: 'aggiornamento disponibile',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version', // TODO translate
|
LATEST_VERSION: 'Stai usando la versione più recente del firmware {0}',
|
||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Attendere',
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Inizializzazione',
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparazione',
|
||||||
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
AUTO_SCROLL: 'Scorrimento automatico',
|
||||||
DASHBOARD: 'Dashboard', // TODO translate
|
DASHBOARD: 'Pannello di controllo',
|
||||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
DEVELOPER_MODE: 'Modalità sviluppatore',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Byte',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bitmask',
|
||||||
DUPLICATE: 'Duplicate', // TODO translate
|
DUPLICATE: 'Duplicato',
|
||||||
UPGRADE: 'Upgrade', // TODO translate
|
DASHBOARD_1: 'Tutte le entità EMS che sono attive e marcate come preferite, più tutte le entità personalizzate, piani di programmazione e dati dei sensori esterni sono visualizzati di seguito.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'modulo per marcarle.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Questa versione',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Piattaforma',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Tipo di rilascio',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
INTERNET_CONNECTION_REQUIRED: 'Connessione internet richiesta per il controllo automatico delle versioni e l\'aggiornamento',
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio'
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ const nl: Translation = {
|
|||||||
UPLOAD: 'Upload',
|
UPLOAD: 'Upload',
|
||||||
DOWNLOAD: '{{D|d|d}}ownload',
|
DOWNLOAD: '{{D|d|d}}ownload',
|
||||||
INSTALL: 'Installeren',
|
INSTALL: 'Installeren',
|
||||||
|
REINSTALL: 'Opnieuw installeren',
|
||||||
ABORTED: 'afgebroken',
|
ABORTED: 'afgebroken',
|
||||||
FAILED: 'mislukt',
|
FAILED: 'mislukt',
|
||||||
SUCCESSFUL: 'successvol',
|
SUCCESSFUL: 'successvol',
|
||||||
@@ -252,13 +253,13 @@ const nl: Translation = {
|
|||||||
AP_CLIENTS: 'AP Clients',
|
AP_CLIENTS: 'AP Clients',
|
||||||
AP_MAX_CLIENTS: 'Max Clients',
|
AP_MAX_CLIENTS: 'Max Clients',
|
||||||
AP_LOCAL_IP: 'Local IP',
|
AP_LOCAL_IP: 'Local IP',
|
||||||
NETWORK_SCAN: 'Scan WiFi Networken',
|
NETWORK_SCAN: 'Scan WiFi Netwerken',
|
||||||
IDLE: 'Idle',
|
IDLE: 'Idle',
|
||||||
LOST: 'Verloren',
|
LOST: 'Verloren',
|
||||||
SCANNING: 'Scannen',
|
SCANNING: 'Scannen',
|
||||||
SCAN_AGAIN: 'Opnieuw scannen',
|
SCAN_AGAIN: 'Opnieuw scannen',
|
||||||
NETWORK_SCANNER: 'Netwerk Scanner',
|
NETWORK_SCANNER: 'Netwerk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
NETWORK_NO_WIFI: 'Geen WiFi netwerken 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',
|
NETWORK_BLANK_BSSID: 'laat leeg om alleen SSID te bebruiken',
|
||||||
TX_POWER: 'Tx Vermogen',
|
TX_POWER: 'Tx Vermogen',
|
||||||
@@ -273,7 +274,7 @@ const nl: Translation = {
|
|||||||
NETWORK_SUBNET: 'Subnetmasker',
|
NETWORK_SUBNET: 'Subnetmasker',
|
||||||
NETWORK_DNS: 'DNS Servers',
|
NETWORK_DNS: 'DNS Servers',
|
||||||
ADDRESS_OF: '{0} Address',
|
ADDRESS_OF: '{0} Address',
|
||||||
ADMINISTRATOR: 'Administrator',
|
ADMINISTRATOR: 'Administrator',
|
||||||
GUEST: 'Gast',
|
GUEST: 'Gast',
|
||||||
NEW: 'Nieuwe',
|
NEW: 'Nieuwe',
|
||||||
NEW_NAME_OF: 'Hernoem {0}',
|
NEW_NAME_OF: 'Hernoem {0}',
|
||||||
@@ -320,7 +321,7 @@ const nl: Translation = {
|
|||||||
DOWNLOAD_UPLOAD_1: 'Download en upload instellingen en firmware',
|
DOWNLOAD_UPLOAD_1: 'Download en upload instellingen en firmware',
|
||||||
MODULES: 'Module',
|
MODULES: 'Module',
|
||||||
MODULES_1: 'Externe modules activeren of deactiveren',
|
MODULES_1: 'Externe modules activeren of deactiveren',
|
||||||
MODULES_UPDATED: 'Modules geüpdatet',
|
MODULES_UPDATED: 'Modules geüpdatet',
|
||||||
MODULES_DESCRIPTION: 'Klik op de module om EMS-ESP library modules te activeren of te deactiveren',
|
MODULES_DESCRIPTION: 'Klik op de module om EMS-ESP library modules te activeren of te deactiveren',
|
||||||
MODULES_NONE: 'Geen externe modules gedetecteerd',
|
MODULES_NONE: 'Geen externe modules gedetecteerd',
|
||||||
RENAME: 'Hernoemen',
|
RENAME: 'Hernoemen',
|
||||||
@@ -331,19 +332,18 @@ const nl: Translation = {
|
|||||||
ALLVALUES: 'All waarden',
|
ALLVALUES: 'All waarden',
|
||||||
SPECIAL_FUNCTIONS: 'Speciale functies',
|
SPECIAL_FUNCTIONS: 'Speciale functies',
|
||||||
WAIT_FIRMWARE: 'Firmware wordt geüpload en geïnstalleerd',
|
WAIT_FIRMWARE: 'Firmware wordt geüpload en geïnstalleerd',
|
||||||
INSTALL_VERSION: 'Hiermee wordt versie {0} geïnstalleerd. Weet je het zeker?',
|
INSTALL_VERSION: 'Hiermee wordt versie {1} {0}. Weet je het zeker?',
|
||||||
UPGRADE_AVAILABLE: 'Er is een firmware-upgrade beschikbaar!',
|
UPDATE_AVAILABLE: 'update beschikbaar',
|
||||||
LATEST_VERSION: 'U gebruikt de nieuwste firmwareversie',
|
LATEST_VERSION: 'U gebruikt de nieuwste {0} firmwareversie',
|
||||||
PLEASE_WAIT: 'Een ogenblik geduld',
|
PLEASE_WAIT: 'Een ogenblik geduld',
|
||||||
RESTARTING_PRE: 'Initialiseren',
|
RESTARTING_PRE: 'Initialiseren',
|
||||||
RESTARTING_POST: 'Voorbereiding',
|
RESTARTING_POST: 'Voorbereiding',
|
||||||
AUTO_SCROLL: 'Automatisch Scrollen',
|
AUTO_SCROLL: 'Automatisch Scrollen',
|
||||||
DASHBOARD: 'Dashboard',
|
DASHBOARD: 'Dashboard',
|
||||||
DEVELOPER_MODE: 'Ontwikkelaarsmodus',
|
DEVELOPER_MODE: 'Ontwikkelaarsmodus',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bytes',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bit Mask',
|
||||||
DUPLICATE: 'Duplicaat',
|
DUPLICATE: 'Duplicaat',
|
||||||
UPGRADE: 'Upgraden',
|
|
||||||
DASHBOARD_1: 'Alle EMS-entiteiten die actief zijn en als favoriet zijn gemarkeerd, plus alle aangepaste entiteiten en externe sensorgegevens worden hieronder weergegeven.',
|
DASHBOARD_1: 'Alle EMS-entiteiten die actief zijn en als favoriet zijn gemarkeerd, plus alle aangepaste entiteiten en externe sensorgegevens worden hieronder weergegeven.',
|
||||||
NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de',
|
NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de',
|
||||||
NO_DATA_2: 'module om ze te markeren.',
|
NO_DATA_2: 'module om ze te markeren.',
|
||||||
@@ -351,8 +351,8 @@ const nl: Translation = {
|
|||||||
THIS_VERSION: 'Deze Versie',
|
THIS_VERSION: 'Deze Versie',
|
||||||
PLATFORM: 'Platform',
|
PLATFORM: 'Platform',
|
||||||
RELEASE_TYPE: 'Release Typ',
|
RELEASE_TYPE: 'Release Typ',
|
||||||
REINSTALL: 'Opnieuw Installeren',
|
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internetverbinding vereist voor automatische versiecontrole en -upgrade',
|
INTERNET_CONNECTION_REQUIRED: 'Internetverbinding vereist voor automatische versiecontrole en -upgrade',
|
||||||
|
SWITCH_RELEASE_TYPE: 'Switch naar {0} release'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
@@ -43,7 +43,7 @@ const no: Translation = {
|
|||||||
RESET: 'Nullstill',
|
RESET: 'Nullstill',
|
||||||
APPLY_CHANGES: 'Utfør endringer({0})',
|
APPLY_CHANGES: 'Utfør endringer({0})',
|
||||||
UPDATE: 'Oppdater',
|
UPDATE: 'Oppdater',
|
||||||
EXECUTE: 'Execute', // TODO translate
|
EXECUTE: 'Utfør',
|
||||||
REMOVE: 'Fjern',
|
REMOVE: 'Fjern',
|
||||||
PROBLEM_UPDATING: 'Problem med oppdatering',
|
PROBLEM_UPDATING: 'Problem med oppdatering',
|
||||||
PROBLEM_LOADING: 'Problem med opplasting',
|
PROBLEM_LOADING: 'Problem med opplasting',
|
||||||
@@ -72,7 +72,7 @@ const no: Translation = {
|
|||||||
TX_ISSUES: 'Tx problemer - prøv en annen Tx Modus',
|
TX_ISSUES: 'Tx problemer - prøv en annen Tx Modus',
|
||||||
DISCONNECTED: 'Frakoblet',
|
DISCONNECTED: 'Frakoblet',
|
||||||
EMS_SCAN: 'Er du sikker på du vil starte full søking av EMS bussen?',
|
EMS_SCAN: 'Er du sikker på du vil starte full søking av EMS bussen?',
|
||||||
DATA_TRAFFIC: 'Data Traffic', // TODO translate
|
DATA_TRAFFIC: 'Data trafikk',
|
||||||
EMS_DEVICE: 'EMS Enhet',
|
EMS_DEVICE: 'EMS Enhet',
|
||||||
SUCCESS: 'VELLYKKET',
|
SUCCESS: 'VELLYKKET',
|
||||||
FAIL: 'MISLYKKET',
|
FAIL: 'MISLYKKET',
|
||||||
@@ -115,9 +115,9 @@ const no: Translation = {
|
|||||||
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',
|
||||||
REMOTE_TIMEOUT: 'Remote timeout',
|
REMOTE_TIMEOUT: 'Remote timeout',
|
||||||
REMOTE_TIMEOUT_EN: 'Disable remote control on missing room temperature', // TODO translate
|
REMOTE_TIMEOUT_EN: 'Deaktiver fjernstyring på manglende romtemperatur',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
HEATINGOFF: 'Start kjele med tvingt oppvarming av',
|
||||||
MIN_DURATION: 'Wait time',
|
MIN_DURATION: 'Ventetid',
|
||||||
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,6 +162,7 @@ const no: Translation = {
|
|||||||
UPLOAD: 'Opplasning',
|
UPLOAD: 'Opplasning',
|
||||||
DOWNLOAD: '{{N|n|n}}edlasting',
|
DOWNLOAD: '{{N|n|n}}edlasting',
|
||||||
INSTALL: 'Installer',
|
INSTALL: 'Installer',
|
||||||
|
REINSTALL: 'Ominstaller',
|
||||||
ABORTED: 'avbrutt',
|
ABORTED: 'avbrutt',
|
||||||
FAILED: 'feilet',
|
FAILED: 'feilet',
|
||||||
SUCCESSFUL: 'vellykket',
|
SUCCESSFUL: 'vellykket',
|
||||||
@@ -174,9 +175,9 @@ const no: Translation = {
|
|||||||
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?',
|
||||||
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
|
AVAILABLE_VERSION: 'Tilgjengelige versjoner',
|
||||||
STABLE: 'Stable', // TODO translate
|
STABLE: 'Stabil',
|
||||||
DEVELOPMENT: 'Development',
|
DEVELOPMENT: 'Utvikling',
|
||||||
UPTIME: 'System Oppetid',
|
UPTIME: 'System Oppetid',
|
||||||
FREE_MEMORY: 'Ledig Memory',
|
FREE_MEMORY: 'Ledig Memory',
|
||||||
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
PSRAM: 'PSRAM (Størrelse / Ledig)',
|
||||||
@@ -185,9 +186,9 @@ const no: Translation = {
|
|||||||
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',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
|
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
|
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
|
||||||
ERROR: 'Ukjent feil, prøv igjen',
|
ERROR: 'Ukjent feil, prøv igjen',
|
||||||
TIME_SET: 'Still in tid',
|
TIME_SET: 'Still in tid',
|
||||||
MANAGE_USERS: 'Administrer Brukere',
|
MANAGE_USERS: 'Administrer Brukere',
|
||||||
@@ -223,7 +224,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_INT_WATER: 'Vannmoduler',
|
||||||
MQTT_QUEUE: 'MQTT Queue',
|
MQTT_QUEUE: 'MQTT Queue',
|
||||||
DEFAULT: 'Standard',
|
DEFAULT: 'Standard',
|
||||||
MQTT_ENTITY_FORMAT: 'Enhets ID format',
|
MQTT_ENTITY_FORMAT: 'Enhets ID format',
|
||||||
@@ -260,7 +261,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',
|
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
NETWORK_BLANK_BSSID: 'la feltet være blankt for å bruke kun SSID',
|
||||||
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',
|
||||||
@@ -297,62 +298,61 @@ const no: Translation = {
|
|||||||
SCHEDULE_TIMER_1: 'ved oppstart',
|
SCHEDULE_TIMER_1: 'ved oppstart',
|
||||||
SCHEDULE_TIMER_2: 'hvert minutt',
|
SCHEDULE_TIMER_2: 'hvert minutt',
|
||||||
SCHEDULE_TIMER_3: 'hver time',
|
SCHEDULE_TIMER_3: 'hver time',
|
||||||
CUSTOM_ENTITIES: 'Custom Entities', // TODO translate
|
CUSTOM_ENTITIES: 'Personlige entiteter',
|
||||||
ENTITIES_HELP_1: 'Fetch custom entities from the EMS bus', // TODO translate
|
ENTITIES_HELP_1: 'Hent personlige entiteter fra EMS bussen',
|
||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entiteter oppdatert',
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Skrivbar',
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Viser',
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Søk',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)', // TODO translate
|
CERT: 'TLS rot sertifikat (la feltet stå blankt for usikkert)',
|
||||||
ENABLE_TLS: 'Aktiviser TLS',
|
ENABLE_TLS: 'Aktiviser TLS',
|
||||||
ON: 'On', // TODO translate
|
ON: 'På',
|
||||||
OFF: 'Off', // TODO translate
|
OFF: 'Av',
|
||||||
POLARITY: 'Polarity', // TODO translate
|
POLARITY: 'Polarity',
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
ACTIVEHIGH: 'Active High',
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
ACTIVELOW: 'Active Low',
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
UNCHANGED: 'Unchanged',
|
||||||
ALWAYS: 'Always', // TODO translate
|
ALWAYS: 'Always',
|
||||||
ACTIVITY: 'Activity', // TODO translate
|
ACTIVITY: 'Aktivitet',
|
||||||
CONFIGURE: 'Configure {0}', // TODO translate
|
CONFIGURE: 'Konfigurer {0}',
|
||||||
SYSTEM_MEMORY: 'System Memory', // TODO translate
|
SYSTEM_MEMORY: 'System Memory',
|
||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users',
|
||||||
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware', // TODO translate
|
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware',
|
||||||
MODULES: 'Module', // TODO translate
|
MODULES: 'Modul',
|
||||||
MODULES_1: 'Aktiver eller deaktiver eksterne moduler',
|
MODULES_1: 'Aktiver eller deaktiver eksterne moduler',
|
||||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
MODULES_UPDATED: 'Moduler oppdatert',
|
||||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
MODULES_DESCRIPTION: 'Klikk på modulen for å aktivere eller deaktivere EMS-ESP biblioteksmoduler',
|
||||||
MODULES_NONE: 'No external modules detected', // TODO translate
|
MODULES_NONE: 'Ingen eksterne moduler funnet',
|
||||||
RENAME: 'Rename', // TODO translate
|
RENAME: 'Gi nytt navn',
|
||||||
ENABLE_MODBUS: 'Aktiver Modbus',
|
ENABLE_MODBUS: 'Aktiver Modbus',
|
||||||
VIEW_LOG: 'View log to diagnose issues', // TODO translate
|
VIEW_LOG: 'Se logg for å diagnostisere problemer',
|
||||||
UPLOAD_DRAG: 'drag and drop a file here or click to select one', // TODO translate
|
UPLOAD_DRAG: 'dra og slippe en fil her eller klikk for å velge en',
|
||||||
SERVICES: 'Services', // TODO translate
|
SERVICES: 'Tjenester',
|
||||||
ALLVALUES: 'All Values', // TODO translate
|
ALLVALUES: 'Alle verdier',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
SPECIAL_FUNCTIONS: 'Spesielle funksjoner',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
WAIT_FIRMWARE: 'Firmware er i opplasting og installasjon',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
INSTALL_VERSION: 'Dette vil {0} versjon {1}. Er du sikker?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
UPDATE_AVAILABLE: 'oppdatering tilgjengelig',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version', // TODO translate
|
LATEST_VERSION: 'Du bruker den nyeste {0} firmware versjonen',
|
||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Vennligst vent',
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initialiserer',
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Forbereder',
|
||||||
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
AUTO_SCROLL: 'Automatisk rulling',
|
||||||
DASHBOARD: 'Dashboard', // TODO translate
|
DASHBOARD: 'Dashboard',
|
||||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
DEVELOPER_MODE: 'Utvikler modus',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bytes',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bitmask',
|
||||||
DUPLICATE: 'Duplicate', // TODO translate
|
DUPLICATE: 'Duplikat',
|
||||||
UPGRADE: 'Upgrade', // TODO translate
|
DASHBOARD_1: 'Alle EMS enheter som er aktive og merket som favoritt, pluss alle personlige enheter, planlegg og eksterne sensor data er vist nedenfor.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'modul for å markere dem.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Denne versjonen',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Plattform',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Utgivelses type',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
INTERNET_CONNECTION_REQUIRED: 'Internettilkobling kreves for automatisk versjonskontroll og oppgradering',
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse'
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const pl: BaseTranslation = {
|
|||||||
TX_ISSUES: 'problem z zapisem na magistralę EMS, spróbuj wybrać inny "Tryb transmisji (Tx)"',
|
TX_ISSUES: 'problem z zapisem na magistralę EMS, spróbuj wybrać inny "Tryb transmisji (Tx)"',
|
||||||
DISCONNECTED: 'brak połączenia',
|
DISCONNECTED: 'brak połączenia',
|
||||||
EMS_SCAN: 'Czy na pewno wykonać pełne skanowanie magistrali EMS?',
|
EMS_SCAN: 'Czy na pewno wykonać pełne skanowanie magistrali EMS?',
|
||||||
DATA_TRAFFIC: 'Data Traffic', // TODO translate
|
DATA_TRAFFIC: 'Ruch Danych',
|
||||||
EMS_DEVICE: 'Urządzenie EMS',
|
EMS_DEVICE: 'Urządzenie EMS',
|
||||||
SUCCESS: 'Udane',
|
SUCCESS: 'Udane',
|
||||||
FAIL: 'Nieudane',
|
FAIL: 'Nieudane',
|
||||||
@@ -115,7 +115,7 @@ const pl: BaseTranslation = {
|
|||||||
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',
|
||||||
REMOTE_TIMEOUT: 'Remote timeout',
|
REMOTE_TIMEOUT: 'Remote timeout',
|
||||||
REMOTE_TIMEOUT_EN: 'Disable remote control on missing room temperature', // TODO translate
|
REMOTE_TIMEOUT_EN: 'Wyłącz kontrolę zdalną przy braku temperatury pomieszczenia',
|
||||||
HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem',
|
HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem',
|
||||||
MIN_DURATION: 'Wait time',
|
MIN_DURATION: 'Wait time',
|
||||||
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
|
||||||
@@ -162,6 +162,7 @@ const pl: BaseTranslation = {
|
|||||||
UPLOAD: 'Wysyłanie',
|
UPLOAD: 'Wysyłanie',
|
||||||
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
DOWNLOAD: '{{P|p||P}}obier{{anie|z||z}}',
|
||||||
INSTALL: 'Zainstalować',
|
INSTALL: 'Zainstalować',
|
||||||
|
REINSTALL: 'Zainstalować ponownie',
|
||||||
ABORTED: 'zostało przerwane!',
|
ABORTED: 'zostało przerwane!',
|
||||||
FAILED: 'nie powiodł{{o|a|}} się!',
|
FAILED: 'nie powiodł{{o|a|}} się!',
|
||||||
SUCCESSFUL: 'powiodło się.',
|
SUCCESSFUL: 'powiodło się.',
|
||||||
@@ -174,9 +175,9 @@ const pl: BaseTranslation = {
|
|||||||
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?',
|
||||||
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
|
AVAILABLE_VERSION: 'Najnowsze dostępne wersje',
|
||||||
STABLE: 'Stable', // TODO translate
|
STABLE: 'Stabilna',
|
||||||
DEVELOPMENT: 'Testowe',
|
DEVELOPMENT: 'Testowa',
|
||||||
UPTIME: 'Czas działania systemu',
|
UPTIME: 'Czas działania systemu',
|
||||||
FREE_MEMORY: 'Wolne Memory',
|
FREE_MEMORY: 'Wolne Memory',
|
||||||
PSRAM: 'PSRAM (rozmiar / wolne)',
|
PSRAM: 'PSRAM (rozmiar / wolne)',
|
||||||
@@ -185,9 +186,9 @@ const pl: BaseTranslation = {
|
|||||||
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',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
|
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
|
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
|
||||||
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
||||||
TIME_SET: 'Zegar został ustawiony.',
|
TIME_SET: 'Zegar został ustawiony.',
|
||||||
MANAGE_USERS: 'Zarządzanie użytkownikami',
|
MANAGE_USERS: 'Zarządzanie użytkownikami',
|
||||||
@@ -318,41 +319,40 @@ const pl: BaseTranslation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
||||||
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
||||||
DOWNLOAD_UPLOAD_1: 'Pobieranie/wysyłanie ustawień i firmware',
|
DOWNLOAD_UPLOAD_1: 'Pobieranie/wysyłanie ustawień i firmware',
|
||||||
MODULES: 'Module', // TODO translate
|
MODULES: 'Moduł',
|
||||||
MODULES_1: 'Aktywuj lub dezaktywuj moduły zewnętrzne',
|
MODULES_1: 'Aktywuj lub dezaktywuj moduły zewnętrzne',
|
||||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
MODULES_UPDATED: 'Zaktualizowano moduły',
|
||||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
MODULES_DESCRIPTION: 'Kliknij na moduł aby aktywować lub dezaktywować bibliotekę modułów EMS-ESP',
|
||||||
MODULES_NONE: 'No external modules detected', // TODO translate
|
MODULES_NONE: 'Brak wykrytych modułów zewnętrznych',
|
||||||
RENAME: 'Rename', // TODO translate
|
RENAME: 'Zmień nazwę',
|
||||||
ENABLE_MODBUS: 'Aktywuj Modbus',
|
ENABLE_MODBUS: 'Aktywuj Modbus',
|
||||||
VIEW_LOG: 'View log to diagnose issues', // TODO translate
|
VIEW_LOG: 'Zdiagnozuj problemy',
|
||||||
UPLOAD_DRAG: 'drag and drop a file here or click to select one', // TODO translate
|
UPLOAD_DRAG: 'przeciągnij i upuść plik lub kliknij tutaj',
|
||||||
SERVICES: 'Services', // TODO translate
|
SERVICES: 'Usługi',
|
||||||
ALLVALUES: 'All Values', // TODO translate
|
ALLVALUES: 'Wszystkie wartości',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
SPECIAL_FUNCTIONS: 'Specjalne funkcje',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
WAIT_FIRMWARE: 'Firma jest wysyłana i instaluje się',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
INSTALL_VERSION: 'To zainstaluje wersję {1} {0}. Jesteś pewny?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
UPDATE_AVAILABLE: 'aktualizacja dostępna',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version', // TODO translate
|
LATEST_VERSION: 'Jesteś używając najnowszej wersji firmware {0}',
|
||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Proszę czekać',
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Inicjalizacja',
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Przygotowanie',
|
||||||
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
AUTO_SCROLL: 'Auto Scroll',
|
||||||
DASHBOARD: 'Dashboard', // TODO translate
|
DASHBOARD: 'Pulpit',
|
||||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
DEVELOPER_MODE: 'Tryb programisty',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bajty',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bit Mask',
|
||||||
DUPLICATE: 'Duplicate', // TODO translate
|
DUPLICATE: 'Duplicate',
|
||||||
UPGRADE: 'Upgrade', // TODO translate
|
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'moduł do ich oznaczenia.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Ta wersja',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Platforma',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Typ wydania',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
INTERNET_CONNECTION_REQUIRED: 'Połączenie internetowe jest wymagane do automatycznej kontroli wersji i aktualizacji',
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie'
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading', // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
@@ -155,13 +155,14 @@ const sk: Translation = {
|
|||||||
NAME: 'Názov',
|
NAME: 'Názov',
|
||||||
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
||||||
SUPPORT_INFORMATION: 'Informácie pre podporu',
|
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_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_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_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_4: 'nezabudnite si stiahnuť a pripojiť informácie o vašom systéme, aby ste mohli rýchlejšie reagovať pri nahlasovaní problému',
|
||||||
UPLOAD: 'Nahrať',
|
UPLOAD: 'Nahrať',
|
||||||
DOWNLOAD: '{{S|s|s}}tiahnuť',
|
DOWNLOAD: '{{S|s|s}}tiahnuť',
|
||||||
INSTALL: 'Inštalovať',
|
INSTALL: 'Inštalovať',
|
||||||
|
REINSTALL: 'Inštalovať znova',
|
||||||
ABORTED: 'zrušené',
|
ABORTED: 'zrušené',
|
||||||
FAILED: 'chybné',
|
FAILED: 'chybné',
|
||||||
SUCCESSFUL: 'úspešné',
|
SUCCESSFUL: 'úspešné',
|
||||||
@@ -187,7 +188,7 @@ const sk: Translation = {
|
|||||||
COMPACT: 'Kompaktné',
|
COMPACT: 'Kompaktné',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení',
|
DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení',
|
||||||
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
|
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem',
|
||||||
ERROR: 'Neočakávaná chyba, prosím skúste to znova',
|
ERROR: 'Neočakávaná chyba, prosím skúste to znova',
|
||||||
TIME_SET: 'Nastavený čas',
|
TIME_SET: 'Nastavený čas',
|
||||||
MANAGE_USERS: 'Správa používateľov',
|
MANAGE_USERS: 'Správa používateľov',
|
||||||
@@ -323,7 +324,7 @@ const sk: Translation = {
|
|||||||
MODULES_UPDATED: 'Aktualizované moduly',
|
MODULES_UPDATED: 'Aktualizované moduly',
|
||||||
MODULES_DESCRIPTION: 'Kliknutím na modul aktivujete alebo deaktivujete moduly knižnice EMS-ESP',
|
MODULES_DESCRIPTION: 'Kliknutím na modul aktivujete alebo deaktivujete moduly knižnice EMS-ESP',
|
||||||
MODULES_NONE: 'Neboli zistené žiadne externé moduly',
|
MODULES_NONE: 'Neboli zistené žiadne externé moduly',
|
||||||
RENAME: 'Premenovať',
|
RENAME: 'Premenovať',
|
||||||
ENABLE_MODBUS: 'Povoliť Modbus',
|
ENABLE_MODBUS: 'Povoliť Modbus',
|
||||||
VIEW_LOG: 'Zobrazte log na diagnostiku problémov',
|
VIEW_LOG: 'Zobrazte log na diagnostiku problémov',
|
||||||
UPLOAD_DRAG: 'presuňte sem súbor alebo ho kliknutím vyberte',
|
UPLOAD_DRAG: 'presuňte sem súbor alebo ho kliknutím vyberte',
|
||||||
@@ -331,19 +332,18 @@ const sk: Translation = {
|
|||||||
ALLVALUES: 'Všetky hodnoty',
|
ALLVALUES: 'Všetky hodnoty',
|
||||||
SPECIAL_FUNCTIONS: 'Špeciálne funkcie',
|
SPECIAL_FUNCTIONS: 'Špeciálne funkcie',
|
||||||
WAIT_FIRMWARE: 'Firmvér sa nahráva a inštaluje',
|
WAIT_FIRMWARE: 'Firmvér sa nahráva a inštaluje',
|
||||||
INSTALL_VERSION: 'Týmto sa inštalovať verzia {0}. Si si istý?',
|
INSTALL_VERSION: 'Týmto sa {0} verzia {1}. Si si istý?',
|
||||||
UPGRADE_AVAILABLE: 'K dispozícii je aktualizácia firmvéru!',
|
UPDATE_AVAILABLE: 'dostupná aktualizácia',
|
||||||
LATEST_VERSION: 'Používate poslednú verziu firmvéru',
|
LATEST_VERSION: 'Používate poslednú {0} verziu firmvéru',
|
||||||
PLEASE_WAIT: 'Čakajte prosím',
|
PLEASE_WAIT: 'Čakajte prosím',
|
||||||
RESTARTING_PRE: 'Prebieha inicializácia',
|
RESTARTING_PRE: 'Prebieha inicializácia',
|
||||||
RESTARTING_POST: 'Príprava',
|
RESTARTING_POST: 'Príprava',
|
||||||
AUTO_SCROLL: 'Automatické rolovanie',
|
AUTO_SCROLL: 'Automatické rolovanie',
|
||||||
DASHBOARD: 'Panel',
|
DASHBOARD: 'Panel',
|
||||||
DEVELOPER_MODE: 'Režim vývojára',
|
DEVELOPER_MODE: 'Režim vývojára',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bytov',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bitová maska',
|
||||||
DUPLICATE: 'Duplicitné',
|
DUPLICATE: 'Duplicitné',
|
||||||
UPGRADE: 'Inovovať',
|
|
||||||
DASHBOARD_1: 'Všetky entity EMS, ktoré sú aktívne a označené ako obľúbené, plus všetky vlastné entity, plány a údaje externých senzorov sú zobrazené nižšie.',
|
DASHBOARD_1: 'Všetky entity EMS, ktoré sú aktívne a označené ako obľúbené, plus všetky vlastné entity, plány a údaje externých senzorov sú zobrazené nižšie.',
|
||||||
NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite',
|
NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite',
|
||||||
NO_DATA_2: 'modul na ich označenie.',
|
NO_DATA_2: 'modul na ich označenie.',
|
||||||
@@ -351,8 +351,8 @@ const sk: Translation = {
|
|||||||
THIS_VERSION: 'Táto verzia',
|
THIS_VERSION: 'Táto verzia',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Typ vydania',
|
RELEASE_TYPE: 'Typ vydania',
|
||||||
REINSTALL: 'Preinštalovať',
|
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internetové pripojenie je potrebné pre automatickú kontrolu a aktualizáciu',
|
INTERNET_CONNECTION_REQUIRED: 'Internetové pripojenie je potrebné pre automatickú kontrolu a aktualizáciu',
|
||||||
|
SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sk;
|
export default sk;
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ const sv: Translation = {
|
|||||||
UPLOAD: 'Uppladdning',
|
UPLOAD: 'Uppladdning',
|
||||||
DOWNLOAD: '{{N|n|n}}edladdning',
|
DOWNLOAD: '{{N|n|n}}edladdning',
|
||||||
INSTALL: 'Installera',
|
INSTALL: 'Installera',
|
||||||
|
REINSTALL: 'Återinstallera',
|
||||||
ABORTED: 'Avbruten',
|
ABORTED: 'Avbruten',
|
||||||
FAILED: 'Misslyckades',
|
FAILED: 'Misslyckades',
|
||||||
SUCCESSFUL: 'Lyckades',
|
SUCCESSFUL: 'Lyckades',
|
||||||
@@ -187,7 +188,7 @@ const sv: Translation = {
|
|||||||
COMPACT: 'Komprimerad',
|
COMPACT: 'Komprimerad',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar',
|
DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar',
|
||||||
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
|
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här',
|
||||||
ERROR: 'Okänt fel, var god försök igen',
|
ERROR: 'Okänt fel, var god försök igen',
|
||||||
TIME_SET: 'Ställ in tid',
|
TIME_SET: 'Ställ in tid',
|
||||||
MANAGE_USERS: 'Användare',
|
MANAGE_USERS: 'Användare',
|
||||||
@@ -331,28 +332,27 @@ const sv: Translation = {
|
|||||||
ALLVALUES: 'Alla värden',
|
ALLVALUES: 'Alla värden',
|
||||||
SPECIAL_FUNCTIONS: 'Specialfunktioner',
|
SPECIAL_FUNCTIONS: 'Specialfunktioner',
|
||||||
WAIT_FIRMWARE: 'Firmware laddas upp och installeras',
|
WAIT_FIRMWARE: 'Firmware laddas upp och installeras',
|
||||||
INSTALL_VERSION: 'Det här kommer installera version {0}. Är du säker?',
|
INSTALL_VERSION: 'Det här kommer {0} version {1}. Är du säker?',
|
||||||
UPGRADE_AVAILABLE: 'Det finns en tillgänglig firmwareupgradering!',
|
UPDATE_AVAILABLE: 'uppdatering tillgänglig',
|
||||||
LATEST_VERSION: 'Du använder den senaste firmwareversionen.',
|
LATEST_VERSION: 'Du använder den senaste {0} firmwareversionen.',
|
||||||
PLEASE_WAIT: 'Var god vänta',
|
PLEASE_WAIT: 'Var god vänta',
|
||||||
RESTARTING_PRE: 'Initialiserar',
|
RESTARTING_PRE: 'Initialiserar',
|
||||||
RESTARTING_POST: 'Förbereder',
|
RESTARTING_POST: 'Förbereder',
|
||||||
AUTO_SCROLL: 'Autoskrolla',
|
AUTO_SCROLL: 'Autoskrolla',
|
||||||
DASHBOARD: 'Kontrollpanel',
|
DASHBOARD: 'Kontrollpanel',
|
||||||
DEVELOPER_MODE: 'Utvecklarläge',
|
DEVELOPER_MODE: 'Utvecklarläge',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bytes',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bitmask',
|
||||||
DUPLICATE: 'Dublett',
|
DUPLICATE: 'Dublett',
|
||||||
UPGRADE: 'Uppgradera',
|
DASHBOARD_1: 'Alla EMS-enheter som är aktiva och markerade som favorit, plus alla anpassade entiteter, scheman och externa sensor-data visas nedan.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'modul för att markera dem.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Denna version',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Plattform',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Utgivelsestyp',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internetanslutning krävs för automatisk version kontroll och uppdatering',
|
INTERNET_CONNECTION_REQUIRED: 'Internetanslutning krävs för automatisk version kontroll och uppdatering',
|
||||||
|
SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const tr: Translation = {
|
|||||||
RESET: 'Reset',
|
RESET: 'Reset',
|
||||||
APPLY_CHANGES: 'Apply Changes ({0})',
|
APPLY_CHANGES: 'Apply Changes ({0})',
|
||||||
UPDATE: 'Update',
|
UPDATE: 'Update',
|
||||||
EXECUTE: 'Execute', // TODO translate
|
EXECUTE: 'Uygulamak',
|
||||||
REMOVE: 'Kaldır',
|
REMOVE: 'Kaldır',
|
||||||
PROBLEM_UPDATING: 'Güncelleme Sorunu',
|
PROBLEM_UPDATING: 'Güncelleme Sorunu',
|
||||||
PROBLEM_LOADING: 'Yükleme Sorunu',
|
PROBLEM_LOADING: 'Yükleme Sorunu',
|
||||||
@@ -72,7 +72,7 @@ const tr: Translation = {
|
|||||||
TX_ISSUES: 'Tx sorunu - başka bir Tx Modu deneyin',
|
TX_ISSUES: 'Tx sorunu - başka bir Tx Modu deneyin',
|
||||||
DISCONNECTED: 'Bağlantı kesildi',
|
DISCONNECTED: 'Bağlantı kesildi',
|
||||||
EMS_SCAN: 'EMS Hattında tam bir cihaz taraması başlatmak istediğinizden emin misiniz?',
|
EMS_SCAN: 'EMS Hattında tam bir cihaz taraması başlatmak istediğinizden emin misiniz?',
|
||||||
DATA_TRAFFIC: 'Data Traffic', // TODO translate
|
DATA_TRAFFIC: 'Veri trafiği',
|
||||||
EMS_DEVICE: 'EMS Cihazı',
|
EMS_DEVICE: 'EMS Cihazı',
|
||||||
SUCCESS: 'BAŞARILI',
|
SUCCESS: 'BAŞARILI',
|
||||||
FAIL: 'HATA',
|
FAIL: 'HATA',
|
||||||
@@ -115,8 +115,8 @@ const tr: Translation = {
|
|||||||
READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)',
|
READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)',
|
||||||
UNDERCLOCK_CPU: 'İşlemci hızını düşür',
|
UNDERCLOCK_CPU: 'İşlemci hızını düşür',
|
||||||
REMOTE_TIMEOUT: 'Remote timeout',
|
REMOTE_TIMEOUT: 'Remote timeout',
|
||||||
REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate
|
REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature',
|
||||||
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
|
HEATINGOFF: 'Start boiler with forced heating off',
|
||||||
MIN_DURATION: 'Wait time',
|
MIN_DURATION: 'Wait time',
|
||||||
ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al',
|
ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al',
|
||||||
ENABLE_SHOWER_ALERT: 'Duş Alarmını Devreye Al',
|
ENABLE_SHOWER_ALERT: 'Duş Alarmını Devreye Al',
|
||||||
@@ -162,6 +162,7 @@ const tr: Translation = {
|
|||||||
UPLOAD: 'Yükleme',
|
UPLOAD: 'Yükleme',
|
||||||
DOWNLOAD: '{{İ|i|i}}İndirme',
|
DOWNLOAD: '{{İ|i|i}}İndirme',
|
||||||
INSTALL: 'Düzenlemek',
|
INSTALL: 'Düzenlemek',
|
||||||
|
REINSTALL: 'Yeniden düzenlemek',
|
||||||
ABORTED: 'iptal edildi',
|
ABORTED: 'iptal edildi',
|
||||||
FAILED: 'başarısız',
|
FAILED: 'başarısız',
|
||||||
SUCCESSFUL: 'başarılı',
|
SUCCESSFUL: 'başarılı',
|
||||||
@@ -174,8 +175,8 @@ const tr: Translation = {
|
|||||||
FACTORY_RESET: 'Fabrika ayarına dönme',
|
FACTORY_RESET: 'Fabrika ayarına dönme',
|
||||||
SYSTEM_FACTORY_TEXT: 'Cihaz fabrika ayarlarına döndü ve şimdi yendiden başlatılacak',
|
SYSTEM_FACTORY_TEXT: 'Cihaz fabrika ayarlarına döndü ve şimdi yendiden başlatılacak',
|
||||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?',
|
SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?',
|
||||||
AVAILABLE_VERSION: 'Latest Available Versions', // TODO translate
|
AVAILABLE_VERSION: 'En son kullanılabilir sürümler',
|
||||||
STABLE: 'Stable', // TODO translate
|
STABLE: 'Kararlı',
|
||||||
DEVELOPMENT: 'Geliştirme',
|
DEVELOPMENT: 'Geliştirme',
|
||||||
UPTIME: 'Sistem Çalışma Süresi',
|
UPTIME: 'Sistem Çalışma Süresi',
|
||||||
FREE_MEMORY: 'Yığın Memory',
|
FREE_MEMORY: 'Yığın Memory',
|
||||||
@@ -185,9 +186,9 @@ const tr: Translation = {
|
|||||||
FILESYSTEM: 'Dosya Sistemi (Kullanılmış / Boş)',
|
FILESYSTEM: 'Dosya Sistemi (Kullanılmış / Boş)',
|
||||||
BUFFER_SIZE: 'En fazla bellek boyutu',
|
BUFFER_SIZE: 'En fazla bellek boyutu',
|
||||||
COMPACT: 'Sıkışık',
|
COMPACT: 'Sıkışık',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', // TODO translate
|
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', // TODO translate
|
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', // TODO translate
|
UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
|
||||||
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
|
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
|
||||||
TIME_SET: 'Zaman ayarı',
|
TIME_SET: 'Zaman ayarı',
|
||||||
MANAGE_USERS: 'Kullanıcıları yönet',
|
MANAGE_USERS: 'Kullanıcıları yönet',
|
||||||
@@ -223,7 +224,7 @@ const tr: Translation = {
|
|||||||
MQTT_INT_THERMOSTATS: 'Termostatlar',
|
MQTT_INT_THERMOSTATS: 'Termostatlar',
|
||||||
MQTT_INT_SOLAR: 'Güneş Enerjisi Modülleri',
|
MQTT_INT_SOLAR: 'Güneş Enerjisi Modülleri',
|
||||||
MQTT_INT_MIXER: 'Karışım Modülleri',
|
MQTT_INT_MIXER: 'Karışım Modülleri',
|
||||||
MQTT_INT_WATER: 'Water Modules', // TODO translate
|
MQTT_INT_WATER: 'Su Modülleri',
|
||||||
MQTT_QUEUE: 'MQTT Sırası',
|
MQTT_QUEUE: 'MQTT Sırası',
|
||||||
DEFAULT: 'Varsayılan',
|
DEFAULT: 'Varsayılan',
|
||||||
MQTT_ENTITY_FORMAT: 'Varlık Kimlik biçimi',
|
MQTT_ENTITY_FORMAT: 'Varlık Kimlik biçimi',
|
||||||
@@ -260,7 +261,7 @@ const tr: Translation = {
|
|||||||
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
||||||
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
||||||
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın',
|
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın',
|
||||||
NETWORK_BLANK_BSSID: 'leave blank to use only SSID', // TODO translate
|
NETWORK_BLANK_BSSID: 'sadece SSID kullanmak için boş bırakın',
|
||||||
TX_POWER: 'Aktarım gücü',
|
TX_POWER: 'Aktarım gücü',
|
||||||
HOSTNAME: 'Ana Makine Adı',
|
HOSTNAME: 'Ana Makine Adı',
|
||||||
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
||||||
@@ -280,79 +281,78 @@ const tr: Translation = {
|
|||||||
ENTITY: 'varlık',
|
ENTITY: 'varlık',
|
||||||
MIN: 'min',
|
MIN: 'min',
|
||||||
MAX: 'maks',
|
MAX: 'maks',
|
||||||
BLOCK_NAVIGATE_1: 'You have unsaved changes', // TODO translate
|
BLOCK_NAVIGATE_1: 'Değiştirilmişleriniz var',
|
||||||
BLOCK_NAVIGATE_2: 'If you navigate to a different page, your unsaved changes will be lost. Are you sure you want to leave this page?', // TODO translate
|
BLOCK_NAVIGATE_2: 'Farklı bir sayfaya geçerseniz değiştirilmişleriniz kaybolacak. Bu sayfadan çıkmak istediğinize emin misiniz?',
|
||||||
STAY: 'Stay', // TODO translate
|
STAY: 'Kal',
|
||||||
LEAVE: 'Leave', // TODO translate
|
LEAVE: 'Çık',
|
||||||
SCHEDULER: 'Scheduler', // TODO translate
|
SCHEDULER: 'Zamanlayıcı',
|
||||||
SCHEDULER_HELP_1: 'Automate commands by adding scheduled events below. Set a unique Name to enable/disable activation via API/MQTT', // TODO translate
|
SCHEDULER_HELP_1: 'Komutları zamanlayarak otomatikleştirin. Benzersiz bir ad belirtin API/MQTT aracılığıyla etkinleştirmek/devre dışı bırakma',
|
||||||
SCHEDULER_HELP_2: 'Use 00:00 to trigger once on start-up', // TODO translate
|
SCHEDULER_HELP_2: 'Başlangıçta bir kere tetiklemek için 00:00 kullanın',
|
||||||
SCHEDULE: 'Schedule', // TODO translate
|
SCHEDULE: 'Zamanlama',
|
||||||
TIME: 'Time', // TODO translate
|
TIME: 'Zaman',
|
||||||
TIMER: 'Timer', // TODO translate
|
TIMER: 'Zamanlayıcı',
|
||||||
ONCHANGE: 'Değişimde',
|
ONCHANGE: 'Değişimde',
|
||||||
CONDITION: 'Durum', // TODO translate
|
CONDITION: 'Durum',
|
||||||
IMMEDIATE: 'hemen', // TODO translate
|
IMMEDIATE: 'hemen',
|
||||||
SCHEDULE_UPDATED: 'Schedule updated', // TODO translate
|
SCHEDULE_UPDATED: 'Zamanlama güncellendi',
|
||||||
SCHEDULE_TIMER_1: 'on startup', // TODO translate
|
SCHEDULE_TIMER_1: 'Başlangıçta',
|
||||||
SCHEDULE_TIMER_2: 'every minute', // TODO translate
|
SCHEDULE_TIMER_2: 'her dakikada',
|
||||||
SCHEDULE_TIMER_3: 'every hour', // TODO translate
|
SCHEDULE_TIMER_3: 'her saatte',
|
||||||
CUSTOM_ENTITIES: 'Custom Entities', // TODO translate
|
CUSTOM_ENTITIES: 'Özel Varlıklar',
|
||||||
ENTITIES_HELP_1: 'Fetch custom entities from the EMS bus', // TODO translate
|
ENTITIES_HELP_1: 'Özel varlıkları EMS hattından alın',
|
||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Varlıklar güncellendi',
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Yazılabilir',
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Görüntüleniyor',
|
||||||
SEARCH: 'Search', // TODO translate
|
SEARCH: 'Ara',
|
||||||
CERT: 'TLS root certificate (leave blank for insecure)',
|
CERT: 'TLS kök sertifikası (güvenli olmayan için boş bırakın)',
|
||||||
ENABLE_TLS: 'TLS deveye al',
|
ENABLE_TLS: 'TLS deveye al',
|
||||||
ON: 'On', // TODO translate
|
ON: 'On',
|
||||||
OFF: 'Off', // TODO translate
|
OFF: 'Off',
|
||||||
POLARITY: 'Polarity', // TODO translate
|
POLARITY: 'Polarity',
|
||||||
ACTIVEHIGH: 'Active High', // TODO translate
|
ACTIVEHIGH: 'Aktif Yüksek',
|
||||||
ACTIVELOW: 'Active Low', // TODO translate
|
ACTIVELOW: 'Aktif Düşük',
|
||||||
UNCHANGED: 'Unchanged', // TODO translate
|
UNCHANGED: 'Değiştirilmedi',
|
||||||
ALWAYS: 'Always', // TODO translate
|
ALWAYS: 'Her zaman',
|
||||||
ACTIVITY: 'Activity', // TODO translate
|
ACTIVITY: 'Faaliyet',
|
||||||
CONFIGURE: 'Configure {0}', // TODO translate
|
CONFIGURE: 'Yapılandır {0}',
|
||||||
SYSTEM_MEMORY: 'System Memory', // TODO translate
|
SYSTEM_MEMORY: 'Sistem Belleği',
|
||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'EMS-ESP Uygulama Ayarlarını Değiştir',
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Kullanıcıları ekle veya kaldır',
|
||||||
DOWNLOAD_UPLOAD_1: 'Download and Upload Settings and Firmware', // TODO translate
|
DOWNLOAD_UPLOAD_1: 'Ayarları ve firmware dosyasını indir ve yükle',
|
||||||
MODULES: 'Module', // TODO translate
|
MODULES: 'Modül',
|
||||||
MODULES_1: 'Harici modülleri etkinleştirin veya devre dışı bırakın',
|
MODULES_1: 'Harici modülleri etkinleştirin veya devre dışı bırakın',
|
||||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
MODULES_UPDATED: 'Modülleri güncellendi',
|
||||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
MODULES_DESCRIPTION: 'Modüle tıklayarak etkinleştirin veya devre dışı bırakın EMS-ESP kütüphane modülleri',
|
||||||
MODULES_NONE: 'No external modules detected', // TODO translate
|
MODULES_NONE: 'Hiçbir harici modül tespit edilmedi',
|
||||||
RENAME: 'Rename', // TODO translate
|
RENAME: 'Yeniden Adlandır',
|
||||||
ENABLE_MODBUS: 'Enable Modbus', // TODO translate
|
ENABLE_MODBUS: 'Modbus\'ı etkinleştir',
|
||||||
VIEW_LOG: 'View log to diagnose issues', // TODO translate
|
VIEW_LOG: 'Sorunu tanımlamak için günlüğü görüntüleyin',
|
||||||
UPLOAD_DRAG: 'drag and drop a file here or click to select one', // TODO translate
|
UPLOAD_DRAG: 'Bir dosya buraya sürükleyip bırakın veya seçmek için tıklayın',
|
||||||
SERVICES: 'Services', // TODO translate
|
SERVICES: 'Hizmetler',
|
||||||
ALLVALUES: 'All Values', // TODO translate
|
ALLVALUES: 'Tüm Değerler',
|
||||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
SPECIAL_FUNCTIONS: 'Özel Fonksiyonlar',
|
||||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
WAIT_FIRMWARE: 'Firmware yükleniyor ve yükleniyor',
|
||||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
INSTALL_VERSION: 'Bu {0} sürümü {1} yükleyecek. Emin misiniz?',
|
||||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
UPDATE_AVAILABLE: 'güncellendi!',
|
||||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
LATEST_VERSION: 'En son {0} firmware sürümünü kullanıyorsunuz.',
|
||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Lütfen bekleyin',
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Başlatılıyor',
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Hazırlanıyor',
|
||||||
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
AUTO_SCROLL: 'Otomatik kaydırma',
|
||||||
DASHBOARD: 'Dashboard', // TODO translate
|
DASHBOARD: 'Kontrol Paneli',
|
||||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
DEVELOPER_MODE: 'Geliştirici Modu',
|
||||||
BYTES: 'Bytes', // TODO translate
|
BYTES: 'Bayt',
|
||||||
BITMASK: 'Bit Mask',// TODO translate
|
BITMASK: 'Bit Maskesi',
|
||||||
DUPLICATE: 'Duplicate', // TODO translate
|
DUPLICATE: 'Çift',
|
||||||
UPGRADE: 'Upgrade', // TODO translate
|
DASHBOARD_1: 'Tüm aktif ve Favori olarak işaretlenmiş EMS varlıkları, artı tüm özel varlıklar, zamanlayıcılar ve harici sensör verileri aşağıda görüntüleniyor.',
|
||||||
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', // TODO translate
|
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
|
||||||
NO_DATA_1: 'No favorite EMS entities found yet. Use the', // TODO translate
|
NO_DATA_2: 'modülünü kullanın.',
|
||||||
NO_DATA_2: 'module to mark them.', // TODO translate
|
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
|
||||||
NO_DATA_3: 'To see all available entities go to', // TODO translate
|
THIS_VERSION: 'Bu Sürüm',
|
||||||
THIS_VERSION: 'This Version', // TODO translate
|
PLATFORM: 'Platforma',
|
||||||
PLATFORM: 'Platform', // TODO translate
|
RELEASE_TYPE: 'Sürüm Tipi',
|
||||||
RELEASE_TYPE: 'Release Type', // TODO translate
|
INTERNET_CONNECTION_REQUIRED: 'Otomatik sürüm kontrolü ve güncelleme için internet bağlantısı gereklidir',
|
||||||
REINSTALL: 'Re-install', // TODO translate
|
SWITCH_RELEASE_TYPE: '{0} sürümüne geç'
|
||||||
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading', // TODO translate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tr;
|
export default tr;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const router = createBrowserRouter(
|
|||||||
createRoutesFromElements(<Route path="/*" element={<App />} />)
|
createRoutesFromElements(<Route path="/*" element={<App />} />)
|
||||||
);
|
);
|
||||||
|
|
||||||
createRoot(document.getElementById('root') as HTMLElement).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export const updateValue =
|
|||||||
|
|
||||||
export const updateValueDirty =
|
export const updateValueDirty =
|
||||||
(
|
(
|
||||||
origData,
|
origData: unknown,
|
||||||
dirtyFlags: string[],
|
dirtyFlags: string[],
|
||||||
setDirtyFlags: React.Dispatch<React.SetStateAction<string[]>>,
|
setDirtyFlags: React.Dispatch<React.SetStateAction<string[]>>,
|
||||||
updateDataValue: (unknown) => void
|
updateDataValue: (value: unknown) => void
|
||||||
) =>
|
) =>
|
||||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const updated_value = extractEventValue(event);
|
const updated_value = extractEventValue(event);
|
||||||
|
|||||||
@@ -1,31 +1,108 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
// Target modern browsers for better performance
|
||||||
|
"target": "ES2022",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
||||||
"types": ["node"],
|
// Optimized library selection
|
||||||
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
|
"types": ["node", "vite/client"],
|
||||||
|
|
||||||
|
// JavaScript handling
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"skipLibCheck": true,
|
"checkJs": false,
|
||||||
"esModuleInterop": false,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
// Module system optimized for Vite
|
||||||
"strict": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"composite": true,
|
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
|
||||||
|
// Emit configuration
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"useUnknownInCatchVariables": false,
|
"declaration": false,
|
||||||
|
"declarationMap": false,
|
||||||
|
"sourceMap": false,
|
||||||
|
|
||||||
|
// React/JSX configuration
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"noImplicitAny": false,
|
"jsxImportSource": "react",
|
||||||
"baseUrl": "src",
|
|
||||||
|
// Strict type checking for better code quality
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictBindCallApply": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
|
||||||
|
// Additional checks
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"useUnknownInCatchVariables": true,
|
||||||
|
|
||||||
|
// Performance optimizations
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"skipDefaultLibCheck": true,
|
||||||
|
"incremental": true,
|
||||||
|
"tsBuildInfoFile": ".tsbuildinfo",
|
||||||
|
|
||||||
|
// Path mapping for cleaner imports
|
||||||
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@": ["src"],
|
"@/*": ["src/*"],
|
||||||
"@/*": ["src/*"]
|
"@/components/*": ["src/components/*"],
|
||||||
|
"@/utils/*": ["src/utils/*"],
|
||||||
|
"@/types/*": ["src/types/*"],
|
||||||
|
"@/hooks/*": ["src/hooks/*"],
|
||||||
|
"@/services/*": ["src/services/*"],
|
||||||
|
"@/assets/*": ["src/assets/*"],
|
||||||
|
// Support for bare imports from src directory
|
||||||
|
"App": ["src/App"],
|
||||||
|
"AppRouting": ["src/AppRouting"],
|
||||||
|
"CustomTheme": ["src/CustomTheme"],
|
||||||
|
"SignIn": ["src/SignIn"],
|
||||||
|
"AuthenticatedRouting": ["src/AuthenticatedRouting"],
|
||||||
|
"env": ["src/env"],
|
||||||
|
"components": ["src/components"],
|
||||||
|
"contexts": ["src/contexts"],
|
||||||
|
"i18n": ["src/i18n"],
|
||||||
|
"utils": ["src/utils"],
|
||||||
|
"validators": ["src/validators"],
|
||||||
|
"types": ["src/types"],
|
||||||
|
"api": ["src/api"],
|
||||||
|
"app": ["src/app"],
|
||||||
|
// Wildcard patterns for subdirectories
|
||||||
|
"components/*": ["src/components/*"],
|
||||||
|
"contexts/*": ["src/contexts/*"],
|
||||||
|
"i18n/*": ["src/i18n/*"],
|
||||||
|
"utils/*": ["src/utils/*"],
|
||||||
|
"validators/*": ["src/validators/*"],
|
||||||
|
"types/*": ["src/types/*"],
|
||||||
|
"api/*": ["src/api/*"],
|
||||||
|
"app/*": ["src/app/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "vite.config.ts"],
|
"include": ["src/**/*", "vite.config.ts", "progmem-generator.js"],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"build",
|
||||||
|
".tsbuildinfo",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.spec.tsx"
|
||||||
|
],
|
||||||
|
"ts-node": {
|
||||||
|
"esm": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,331 @@
|
|||||||
import preact from '@preact/preset-vite';
|
import preact from '@preact/preset-vite';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { Plugin } from 'vite';
|
||||||
import viteImagemin from 'vite-plugin-imagemin';
|
import viteImagemin from 'vite-plugin-imagemin';
|
||||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
import zlib from 'zlib';
|
||||||
|
|
||||||
|
// @ts-expect-error - mock server doesn't have type declarations
|
||||||
import mockServer from '../mock-api/mockServer.js';
|
import mockServer from '../mock-api/mockServer.js';
|
||||||
|
|
||||||
export default defineConfig(({ command, mode }) => {
|
// Plugin to display bundle size information
|
||||||
if (command === 'serve') {
|
const bundleSizeReporter = (): Plugin => {
|
||||||
console.log('Preparing for standalone build with server, mode=' + mode);
|
return {
|
||||||
return {
|
name: 'bundle-size-reporter',
|
||||||
plugins: [preact(), viteTsconfigPaths(), mockServer()],
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
server: {
|
writeBundle(options: any, bundle: any) {
|
||||||
open: true,
|
console.log('\n📦 Bundle Size Report:');
|
||||||
port: mode == 'production' ? 4173 : 3000,
|
console.log('='.repeat(50));
|
||||||
proxy: {
|
|
||||||
'/api': {
|
let totalSize = 0;
|
||||||
target: 'http://localhost:3080',
|
const files: Array<{ name: string; size: number; gzipSize?: number }> = [];
|
||||||
changeOrigin: true,
|
|
||||||
secure: false
|
for (const [fileName, chunk] of Object.entries(
|
||||||
},
|
bundle as Record<string, unknown>
|
||||||
'/rest': 'http://localhost:3080',
|
)) {
|
||||||
'/gh': 'http://localhost:3080' // mock for GitHub API
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
if ((chunk as any).type === 'chunk' || (chunk as any).type === 'asset') {
|
||||||
|
const filePath = path.join((options.dir as string) || 'dist', fileName);
|
||||||
|
let size = 0;
|
||||||
|
let gzipSize = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
size = stats.size;
|
||||||
|
totalSize += size;
|
||||||
|
|
||||||
|
// Calculate gzip size
|
||||||
|
const fileContent = fs.readFileSync(filePath);
|
||||||
|
gzipSize = zlib.gzipSync(fileContent).length;
|
||||||
|
|
||||||
|
files.push({
|
||||||
|
name: fileName,
|
||||||
|
size,
|
||||||
|
gzipSize
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Could not read file ${fileName}:`, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'hosted') {
|
// Sort files by size (largest first)
|
||||||
console.log('Preparing for hosted build');
|
files.sort((a, b) => b.size - a.size);
|
||||||
return {
|
|
||||||
plugins: [preact(), viteTsconfigPaths()],
|
|
||||||
build: {
|
|
||||||
chunkSizeWarningLimit: 1024
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Preparing for production, optimized build');
|
// Display individual file sizes
|
||||||
|
files.forEach((file) => {
|
||||||
|
const sizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
const gzipKB = file.gzipSize ? (file.gzipSize / 1024).toFixed(2) : 'N/A';
|
||||||
|
console.log(
|
||||||
|
`📄 ${file.name.padEnd(30)} ${sizeKB.padStart(8)} KB (${gzipKB} KB gzipped)`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
console.log('='.repeat(50));
|
||||||
plugins: [
|
console.log(`📊 Total Bundle Size: ${(totalSize / 1024).toFixed(2)} KB`);
|
||||||
preact(),
|
|
||||||
viteTsconfigPaths(),
|
// Calculate and display gzip total
|
||||||
{
|
const totalGzipSize = files.reduce(
|
||||||
...viteImagemin({
|
(sum, file) => sum + (file.gzipSize || 0),
|
||||||
verbose: false,
|
0
|
||||||
gifsicle: {
|
);
|
||||||
optimizationLevel: 7,
|
console.log(`🗜️ Total Gzipped Size: ${(totalGzipSize / 1024).toFixed(2)} KB`);
|
||||||
interlaced: false
|
|
||||||
},
|
// Show compression ratio
|
||||||
optipng: {
|
const compressionRatio = (
|
||||||
optimizationLevel: 7
|
((totalSize - totalGzipSize) / totalSize) *
|
||||||
},
|
100
|
||||||
mozjpeg: {
|
).toFixed(1);
|
||||||
quality: 20
|
console.log(`📈 Compression Ratio: ${compressionRatio}%`);
|
||||||
},
|
|
||||||
pngquant: {
|
console.log('='.repeat(50));
|
||||||
quality: [0.8, 0.9],
|
}
|
||||||
speed: 4
|
};
|
||||||
},
|
};
|
||||||
svgo: {
|
|
||||||
plugins: [
|
export default defineConfig(
|
||||||
{
|
({ command, mode }: { command: string; mode: string }) => {
|
||||||
name: 'removeViewBox'
|
if (command === 'serve') {
|
||||||
},
|
console.log('Preparing for standalone build with server, mode=' + mode);
|
||||||
{
|
return {
|
||||||
name: 'removeEmptyAttrs',
|
plugins: [
|
||||||
active: false
|
preact({
|
||||||
}
|
// Keep dev tools enabled for development
|
||||||
]
|
devToolsEnabled: true,
|
||||||
|
prefreshEnabled: true
|
||||||
|
}),
|
||||||
|
viteTsconfigPaths(),
|
||||||
|
bundleSizeReporter(), // Add bundle size reporting
|
||||||
|
mockServer()
|
||||||
|
],
|
||||||
|
server: {
|
||||||
|
open: true,
|
||||||
|
port: mode == 'production' ? 4173 : 3000,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:3080',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false
|
||||||
|
},
|
||||||
|
'/rest': 'http://localhost:3080',
|
||||||
|
'/gh': 'http://localhost:3080' // mock for GitHub API
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
enforce: 'pre'
|
|
||||||
},
|
|
||||||
visualizer({
|
|
||||||
template: 'treemap', // or sunburst
|
|
||||||
open: false,
|
|
||||||
gzipSize: true,
|
|
||||||
brotliSize: true,
|
|
||||||
filename: '../analyse.html' // will be saved in project's root
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
build: {
|
|
||||||
// target: 'es2022',
|
|
||||||
chunkSizeWarningLimit: 1024,
|
|
||||||
minify: 'terser',
|
|
||||||
terserOptions: {
|
|
||||||
compress: {
|
|
||||||
passes: 4,
|
|
||||||
arrows: true,
|
|
||||||
drop_console: true,
|
|
||||||
drop_debugger: true,
|
|
||||||
sequences: true
|
|
||||||
},
|
},
|
||||||
mangle: {
|
// Optimize development builds
|
||||||
// toplevel: true
|
build: {
|
||||||
// module: true
|
target: 'es2020',
|
||||||
// properties: {
|
minify: false, // Disable minification for faster dev builds
|
||||||
// regex: /^_/
|
sourcemap: true // Enable source maps for debugging
|
||||||
// }
|
}
|
||||||
},
|
};
|
||||||
ecma: 5,
|
}
|
||||||
enclose: false,
|
|
||||||
keep_classnames: false,
|
|
||||||
keep_fnames: false,
|
|
||||||
ie8: false,
|
|
||||||
module: false,
|
|
||||||
nameCache: null,
|
|
||||||
safari10: false,
|
|
||||||
toplevel: false
|
|
||||||
},
|
|
||||||
|
|
||||||
rollupOptions: {
|
if (mode === 'hosted') {
|
||||||
output: {
|
console.log('Preparing for hosted build');
|
||||||
manualChunks(id: string) {
|
return {
|
||||||
if (id.includes('node_modules')) {
|
plugins: [
|
||||||
// creating a chunk to react routes deps. Reducing the vendor chunk size
|
preact({
|
||||||
if (id.includes('react-router')) {
|
// Enable Preact optimizations for hosted build
|
||||||
return '@react-router';
|
devToolsEnabled: false,
|
||||||
|
prefreshEnabled: false
|
||||||
|
}),
|
||||||
|
viteTsconfigPaths(),
|
||||||
|
bundleSizeReporter() // Add bundle size reporting
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
target: 'es2020',
|
||||||
|
chunkSizeWarningLimit: 512,
|
||||||
|
minify: 'terser',
|
||||||
|
cssMinify: true,
|
||||||
|
assetsInlineLimit: 4096,
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
passes: 3,
|
||||||
|
drop_console: true,
|
||||||
|
drop_debugger: true,
|
||||||
|
dead_code: true,
|
||||||
|
unused: true
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
toplevel: true
|
||||||
|
},
|
||||||
|
ecma: 2020
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
treeshake: {
|
||||||
|
moduleSideEffects: false
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
manualChunks(id: string) {
|
||||||
|
if (id.includes('node_modules')) {
|
||||||
|
if (id.includes('preact')) {
|
||||||
|
return '@preact';
|
||||||
|
}
|
||||||
|
return 'vendor';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
return 'vendor';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
console.log('Preparing for production, optimized build');
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
preact({
|
||||||
|
// Enable Preact optimizations
|
||||||
|
devToolsEnabled: false,
|
||||||
|
prefreshEnabled: false
|
||||||
|
}),
|
||||||
|
viteTsconfigPaths(),
|
||||||
|
// Enable image optimization for size reduction
|
||||||
|
{
|
||||||
|
...viteImagemin({
|
||||||
|
verbose: false,
|
||||||
|
gifsicle: {
|
||||||
|
optimizationLevel: 7,
|
||||||
|
interlaced: false
|
||||||
|
},
|
||||||
|
optipng: {
|
||||||
|
optimizationLevel: 7
|
||||||
|
},
|
||||||
|
mozjpeg: {
|
||||||
|
quality: 20
|
||||||
|
},
|
||||||
|
pngquant: {
|
||||||
|
quality: [0.8, 0.9],
|
||||||
|
speed: 4
|
||||||
|
},
|
||||||
|
svgo: {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
name: 'removeViewBox'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'removeEmptyAttrs',
|
||||||
|
active: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
enforce: 'pre'
|
||||||
|
},
|
||||||
|
visualizer({
|
||||||
|
template: 'treemap', // or sunburst
|
||||||
|
open: false,
|
||||||
|
gzipSize: true,
|
||||||
|
brotliSize: true,
|
||||||
|
filename: '../analyse.html' // will be saved in project's root
|
||||||
|
}),
|
||||||
|
bundleSizeReporter() // Add bundle size reporting
|
||||||
|
],
|
||||||
|
|
||||||
|
build: {
|
||||||
|
// Target modern browsers for smaller bundles
|
||||||
|
target: 'es2020',
|
||||||
|
chunkSizeWarningLimit: 512,
|
||||||
|
minify: 'terser',
|
||||||
|
// Enable CSS minification
|
||||||
|
cssMinify: true,
|
||||||
|
// Optimize asset handling
|
||||||
|
assetsInlineLimit: 4096, // Inline small assets
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
passes: 6,
|
||||||
|
arrows: true,
|
||||||
|
drop_console: true,
|
||||||
|
drop_debugger: true,
|
||||||
|
sequences: true
|
||||||
|
// Additional aggressive compression options
|
||||||
|
// dead_code: true,
|
||||||
|
// hoist_funs: true,
|
||||||
|
// hoist_vars: true,
|
||||||
|
// if_return: true,
|
||||||
|
// join_vars: true,
|
||||||
|
// loops: true,
|
||||||
|
// pure_getters: true,
|
||||||
|
// reduce_vars: true,
|
||||||
|
// side_effects: false,
|
||||||
|
// switches: true,
|
||||||
|
// unsafe: true,
|
||||||
|
// unsafe_arrows: true,
|
||||||
|
// unsafe_comps: true,
|
||||||
|
// unsafe_Function: true,
|
||||||
|
// unsafe_math: true,
|
||||||
|
// unsafe_proto: true,
|
||||||
|
// unsafe_regexp: true,
|
||||||
|
// unsafe_undefined: true,
|
||||||
|
// unused: true
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
toplevel: true, // Enable top-level mangling
|
||||||
|
module: true // Enable module mangling
|
||||||
|
// properties: {
|
||||||
|
// regex: /^_/ // Mangle properties starting with _
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
ecma: 2020, // Updated to modern ECMAScript
|
||||||
|
enclose: false,
|
||||||
|
keep_classnames: false,
|
||||||
|
keep_fnames: false,
|
||||||
|
ie8: false,
|
||||||
|
module: false,
|
||||||
|
safari10: false,
|
||||||
|
toplevel: true // Enable top-level optimization
|
||||||
|
},
|
||||||
|
|
||||||
|
rollupOptions: {
|
||||||
|
// Enable tree shaking
|
||||||
|
treeshake: {
|
||||||
|
moduleSideEffects: false,
|
||||||
|
propertyReadSideEffects: false,
|
||||||
|
tryCatchDeoptimization: false
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
// Optimize chunk naming for better caching
|
||||||
|
chunkFileNames: 'assets/[name]-[hash].js',
|
||||||
|
entryFileNames: 'assets/[name]-[hash].js',
|
||||||
|
assetFileNames: 'assets/[name]-[hash].[ext]',
|
||||||
|
manualChunks(id: string) {
|
||||||
|
if (id.includes('node_modules')) {
|
||||||
|
// More granular chunk splitting for better caching
|
||||||
|
if (id.includes('react-router')) {
|
||||||
|
return '@react-router';
|
||||||
|
}
|
||||||
|
if (id.includes('preact')) {
|
||||||
|
return '@preact';
|
||||||
|
}
|
||||||
|
if (id.includes('uuid')) {
|
||||||
|
return '@uuid';
|
||||||
|
}
|
||||||
|
if (id.includes('axios') || id.includes('fetch')) {
|
||||||
|
return '@http';
|
||||||
|
}
|
||||||
|
if (id.includes('lodash') || id.includes('ramda')) {
|
||||||
|
return '@utils';
|
||||||
|
}
|
||||||
|
return 'vendor';
|
||||||
|
}
|
||||||
|
// Split large application modules
|
||||||
|
if (id.includes('components/')) {
|
||||||
|
return 'components';
|
||||||
|
}
|
||||||
|
if (id.includes('pages/') || id.includes('routes/')) {
|
||||||
|
return 'pages';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
// Enable source maps for debugging (optional)
|
||||||
|
sourcemap: false // Disable for production to save space
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user