mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-09 15:35:51 +00:00
Compare commits
1998 Commits
v3.8.0
...
d18e5b1f14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d18e5b1f14 | ||
|
|
20327d817d | ||
|
|
051c332426 | ||
|
|
a09258325e | ||
|
|
61dca0cbda | ||
|
|
2bff299193 | ||
|
|
1329b13db3 | ||
|
|
29380f0303 | ||
|
|
9dd894f0fe | ||
|
|
6b2370b79d | ||
|
|
dbc636c9bf | ||
|
|
30d1ae5642 | ||
|
|
79aceef382 | ||
|
|
a28e52210a | ||
|
|
0c0660c04b | ||
|
|
08eb294213 | ||
|
|
c9fd076394 | ||
|
|
888baed81a | ||
|
|
4de3955db2 | ||
|
|
25f08c7624 | ||
|
|
35550553be | ||
|
|
06ff219385 | ||
|
|
e705a5629f | ||
|
|
1e8013100c | ||
|
|
62c8f55568 | ||
|
|
cb3c9653ce | ||
|
|
0b5a83f6ae | ||
|
|
a079169005 | ||
|
|
845c51d5f9 | ||
|
|
c40d828749 | ||
|
|
d6d3a034ad | ||
|
|
84ad08887a | ||
|
|
ece08d96ee | ||
|
|
ed0a678020 | ||
|
|
854f4d559a | ||
|
|
f186f2a8f2 | ||
|
|
37107d8500 | ||
|
|
6b68cb7c61 | ||
|
|
a1e0288e09 | ||
|
|
e6c173bdf9 | ||
|
|
dde6a8c5db | ||
|
|
e2750b8572 | ||
|
|
acd23925b5 | ||
|
|
b0db054e11 | ||
|
|
d9b6de0652 | ||
|
|
c54da18822 | ||
|
|
51cea8e757 | ||
|
|
bbb086ea41 | ||
|
|
539e6ed080 | ||
|
|
555801dc5c | ||
|
|
1d33a26318 | ||
|
|
86a20fc97a | ||
|
|
d6e00c4534 | ||
|
|
6f81945da6 | ||
|
|
865c309475 | ||
|
|
77b8b21aea | ||
|
|
2f5edffec6 | ||
|
|
71de64502e | ||
|
|
6994d3559a | ||
|
|
a7d484d218 | ||
|
|
a810c41acd | ||
|
|
2fbfdf94ab | ||
|
|
2d7c8f0863 | ||
|
|
c3b734ab47 | ||
|
|
644abf105d | ||
|
|
5a8a451774 | ||
|
|
dae139aa01 | ||
|
|
b13fcd8939 | ||
|
|
26b42b4eea | ||
|
|
c9005e8aa9 | ||
|
|
6658b11adf | ||
|
|
e542f5809f | ||
|
|
ce1dd6233d | ||
|
|
fe488443da | ||
|
|
b264a39780 | ||
|
|
d2302eaa85 | ||
|
|
a813d38108 | ||
|
|
685a49c212 | ||
|
|
994706c9f2 | ||
|
|
2c8eb534af | ||
|
|
5210fab4cb | ||
|
|
49787d27f1 | ||
|
|
dfe7b46461 | ||
|
|
8a72ab42cb | ||
|
|
c4db8e3914 | ||
|
|
8d0225e595 | ||
|
|
f8257de0dd | ||
|
|
3b3ecc9f1d | ||
|
|
966049d0c9 | ||
|
|
907a65a701 | ||
|
|
f97b8e14e7 | ||
|
|
e65f634b21 | ||
|
|
fc71ed2b9d | ||
|
|
84105acf5d | ||
|
|
def5173692 | ||
|
|
6b31fef1af | ||
|
|
c9c059ca65 | ||
|
|
4d3b31e5a1 | ||
|
|
5a8195d430 | ||
|
|
24a7a607f3 | ||
|
|
061f9ffc52 | ||
|
|
9e17936bfc | ||
|
|
18bb2c4f39 | ||
|
|
7c3782a43f | ||
|
|
3ac807bdd5 | ||
|
|
1111458863 | ||
|
|
99c5e2230c | ||
|
|
3317aa845a | ||
|
|
97cd657336 | ||
|
|
3338f919bd | ||
|
|
7dd13bcab7 | ||
|
|
f226cb359f | ||
|
|
abbba0aa42 | ||
|
|
39b5a52b01 | ||
|
|
b6c3fc5bee | ||
|
|
909bea00df | ||
|
|
9522945e06 | ||
|
|
d6a9f2a731 | ||
|
|
0f30c81554 | ||
|
|
e514ba4bb5 | ||
|
|
38e63e3eaa | ||
|
|
0058324edd | ||
|
|
ac143d607a | ||
|
|
e9e3759db3 | ||
|
|
51d90095aa | ||
|
|
fb09e10f19 | ||
|
|
16c0370443 | ||
|
|
67bb38dcf4 | ||
|
|
049231a36e | ||
|
|
349d6b7375 | ||
|
|
b72b368d3c | ||
|
|
7f9fd44a02 | ||
|
|
a400c5974c | ||
|
|
afca995fe5 | ||
|
|
81504fedc5 | ||
|
|
3da3345683 | ||
|
|
c6c2889306 | ||
|
|
b60f0d260a | ||
|
|
cd750e4777 | ||
|
|
4e5d503b35 | ||
|
|
bd09e17e49 | ||
|
|
835eb743bb | ||
|
|
69a129d80e | ||
|
|
434bf483fd | ||
|
|
2b8e170b40 | ||
|
|
dc9b95f3e7 | ||
|
|
1616b0da0a | ||
|
|
91c457b22b | ||
|
|
70c60647c7 | ||
|
|
c0bea66d27 | ||
|
|
ed7cc078ed | ||
|
|
60b7d6d795 | ||
|
|
947f29cca0 | ||
|
|
d2a13ec0da | ||
|
|
cc39ba409e | ||
|
|
09473f17a0 | ||
|
|
ac9db6256e | ||
|
|
096f628d97 | ||
|
|
bbc2de08a5 | ||
|
|
22312812bb | ||
|
|
df808a2bcf | ||
|
|
d04e7c36f3 | ||
|
|
205d826adb | ||
|
|
3584975acb | ||
|
|
30b9ca4e6c | ||
|
|
7c6ff01ebe | ||
|
|
a54edcaf5b | ||
|
|
e446954844 | ||
|
|
4a2d0d6787 | ||
|
|
9725314135 | ||
|
|
4db8e43648 | ||
|
|
e610f0d57f | ||
|
|
8244af2940 | ||
|
|
cc60062678 | ||
|
|
40f371d23b | ||
|
|
817b791e59 | ||
|
|
25a7aac360 | ||
|
|
37115a174d | ||
|
|
1397f81fd0 | ||
|
|
56365cb403 | ||
|
|
dfd245ee7b | ||
|
|
9c81e4b34d | ||
|
|
67676df131 | ||
|
|
a73b129596 | ||
|
|
4600d886b5 | ||
|
|
e3305ab9db | ||
|
|
0fe45a2405 | ||
|
|
db87213242 | ||
|
|
b0157f288e | ||
|
|
5c3c010d5a | ||
|
|
c804cedd7a | ||
|
|
a9f50d9371 | ||
|
|
65a3226404 | ||
|
|
45690f5418 | ||
|
|
aa30ca99bf | ||
|
|
6836b6197f | ||
|
|
c0ca9d1069 | ||
|
|
5e79e1d57f | ||
|
|
8c732f9f1e | ||
|
|
5e94c2f636 | ||
|
|
69d4163b9d | ||
|
|
b1e974a82c | ||
|
|
34a2b20be8 | ||
|
|
f1fc8d9aae | ||
|
|
b04355e3e1 | ||
|
|
cd3ae5cdf2 | ||
|
|
a261ca23af | ||
|
|
cb96904a5c | ||
|
|
4a2d78f8e1 | ||
|
|
f5af4fb52f | ||
|
|
2037bc3a10 | ||
|
|
64d17d7c65 | ||
|
|
92e2633342 | ||
|
|
96a7ea8a02 | ||
|
|
5c4aaa4510 | ||
|
|
c05e1cb77b | ||
|
|
5879ce4090 | ||
|
|
ac3e5c793c | ||
|
|
64e5d29996 | ||
|
|
b320d8ded2 | ||
|
|
4326fb931b | ||
|
|
ced7051ce7 | ||
|
|
0be1b20996 | ||
|
|
6c55460622 | ||
|
|
421da246ed | ||
|
|
d627404dc2 | ||
|
|
148a721e17 | ||
|
|
f317123c26 | ||
|
|
e4df1887b0 | ||
|
|
34142c3e85 | ||
|
|
6e7f8bdf02 | ||
|
|
3dd9fcfb58 | ||
|
|
35e2954b8b | ||
|
|
59aa63db0f | ||
|
|
7a41a190f8 | ||
|
|
6741232450 | ||
|
|
a811670c5a | ||
|
|
72f08a86cf | ||
|
|
27c471f45f | ||
|
|
e303972d26 | ||
|
|
97bb03d703 | ||
|
|
e9f77c1bde | ||
|
|
81cba6c0a8 | ||
|
|
89029df25e | ||
|
|
3463b6818d | ||
|
|
349843e666 | ||
|
|
96ae3bbbba | ||
|
|
b153364b60 | ||
|
|
ccc40937fb | ||
|
|
909edf394d | ||
|
|
ac8ef646e9 | ||
|
|
3ef279ea10 | ||
|
|
769beeda37 | ||
|
|
f83404c216 | ||
|
|
c239658131 | ||
|
|
be82afd778 | ||
|
|
2156c96368 | ||
|
|
f7f078d82a | ||
|
|
95168cf514 | ||
|
|
6dc601c4a2 | ||
|
|
6b87bbb882 | ||
|
|
abdf2c5037 | ||
|
|
7beec1b80f | ||
|
|
3a0e46f064 | ||
|
|
85cc85a923 | ||
|
|
ca0079c0df | ||
|
|
28b662ad43 | ||
|
|
6bac6bbfeb | ||
|
|
958ec1002b | ||
|
|
438852ecaf | ||
|
|
92d82c0a00 | ||
|
|
7d37267f57 | ||
|
|
5641d53cc3 | ||
|
|
8fc6752290 | ||
|
|
cca6f87500 | ||
|
|
758d76051f | ||
|
|
95f7e66cff | ||
|
|
4e194287c9 | ||
|
|
3545830552 | ||
|
|
074f4c32ed | ||
|
|
b3fec5ed7d | ||
|
|
ffb90b8f9a | ||
|
|
584618043d | ||
|
|
d702c485b7 | ||
|
|
d3561da331 | ||
|
|
0e0aaf37df | ||
|
|
5ec068409f | ||
|
|
8796b6d340 | ||
|
|
bfbb18655d | ||
|
|
9088651e53 | ||
|
|
3e8f379502 | ||
|
|
265c2c4231 | ||
|
|
f671d79280 | ||
|
|
97c89d1d13 | ||
|
|
e0a26a38fa | ||
|
|
038f06e59f | ||
|
|
f4d2bae04f | ||
|
|
d443e275ea | ||
|
|
30d2057e01 | ||
|
|
d952b9aaae | ||
|
|
3402215e8d | ||
|
|
f01031dc26 | ||
|
|
01d4d116b9 | ||
|
|
bc7f82eef1 | ||
|
|
efdb355033 | ||
|
|
87c9fd010f | ||
|
|
930f0e615a | ||
|
|
4dbbdb3290 | ||
|
|
8379b3f5aa | ||
|
|
08124fa4db | ||
|
|
39414db732 | ||
|
|
da57a08005 | ||
|
|
b6b8700c3f | ||
|
|
8ee0789dad | ||
|
|
1eabe86015 | ||
|
|
5fe4b315f3 | ||
|
|
03ec96bf96 | ||
|
|
aa05e37fbb | ||
|
|
959a00c19a | ||
|
|
b42060be3a | ||
|
|
33bb433d7e | ||
|
|
28a5d4ef1a | ||
|
|
b78d47cbd0 | ||
|
|
8a7a1383a7 | ||
|
|
3f5163c1e4 | ||
|
|
fad82c8c68 | ||
|
|
6fc3bf30b6 | ||
|
|
43b3e74c08 | ||
|
|
64c9882d8c | ||
|
|
a690510903 | ||
|
|
c732ec301a | ||
|
|
cc1f16596a | ||
|
|
66c74f85a4 | ||
|
|
db667b9437 | ||
|
|
8799015f59 | ||
|
|
d71b3c64e1 | ||
|
|
6d3083fff4 | ||
|
|
56b2c111b8 | ||
|
|
12ce736580 | ||
|
|
debe90eb8d | ||
|
|
8d318143a4 | ||
|
|
59f90f5d1c | ||
|
|
0efbd0528e | ||
|
|
3218620a0e | ||
|
|
a93921c875 | ||
|
|
fb77b455be | ||
|
|
b64c392c58 | ||
|
|
7bc6cf3910 | ||
|
|
e19e76546e | ||
|
|
b9aaaae90a | ||
|
|
86b395d612 | ||
|
|
6204b9acc7 | ||
|
|
0777f420b0 | ||
|
|
4a6a662aa0 | ||
|
|
66837d399f | ||
|
|
34ff5f12ea | ||
|
|
82d160cabb | ||
|
|
2c85d3829b | ||
|
|
cc258dae16 | ||
|
|
577964befe | ||
|
|
f2500013ab | ||
|
|
98fb6941d2 | ||
|
|
7308b8e73d | ||
|
|
e97cfaf9ee | ||
|
|
fd0734d8d8 | ||
|
|
739f32f045 | ||
|
|
b66b49e812 | ||
|
|
d4b81a2909 | ||
|
|
fb57537e88 | ||
|
|
335b1274cf | ||
|
|
f6d1c87eaf | ||
|
|
5e07e9a11b | ||
|
|
dd0ea5df0e | ||
|
|
2b7f592957 | ||
|
|
db7b5df85d | ||
|
|
1c2534ed8f | ||
|
|
90535d7b94 | ||
|
|
0d3a8fc719 | ||
|
|
d624b9eac9 | ||
|
|
068cbf757c | ||
|
|
738d6f0b0f | ||
|
|
d9551bc4c3 | ||
|
|
722659325a | ||
|
|
927e7c80f4 | ||
|
|
39919b4ad8 | ||
|
|
b5defa552e | ||
|
|
e8fbbe5a1c | ||
|
|
949172128f | ||
|
|
35a8db4581 | ||
|
|
3a74abb4db | ||
|
|
bcc7687b1b | ||
|
|
13aa544214 | ||
|
|
696141721a | ||
|
|
4781eea665 | ||
|
|
2fd6bed485 | ||
|
|
db40d1d381 | ||
|
|
33bde8b407 | ||
|
|
bf5990a992 | ||
|
|
cff4bd0a71 | ||
|
|
28ee0834d8 | ||
|
|
9be1cb1d3e | ||
|
|
81d46fede2 | ||
|
|
664a8e9f5f | ||
|
|
def7501c62 | ||
|
|
1cc4dc52d4 | ||
|
|
978c738f27 | ||
|
|
feeb8500ac | ||
|
|
18a55d4622 | ||
|
|
29ea67f438 | ||
|
|
a3df77171b | ||
|
|
aa6f5c50b2 | ||
|
|
53a43ca147 | ||
|
|
da76fe3871 | ||
|
|
84af132e2c | ||
|
|
712a8537c9 | ||
|
|
bb22386f7f | ||
|
|
89dfe11ee3 | ||
|
|
be1e08af9c | ||
|
|
68ebcdded4 | ||
|
|
4afe041880 | ||
|
|
8b690d23da | ||
|
|
62c7fb671b | ||
|
|
5a82064a88 | ||
|
|
4ae4000944 | ||
|
|
616c73f658 | ||
|
|
b698485814 | ||
|
|
b4036bf8cd | ||
|
|
4b457d6cdb | ||
|
|
425b44e334 | ||
|
|
41bf293db3 | ||
|
|
af349edd54 | ||
|
|
5b303bd58a | ||
|
|
b992f90fe2 | ||
|
|
92c34dddba | ||
|
|
1475fc094d | ||
|
|
48f7b48216 | ||
|
|
cd054b293a | ||
|
|
ea6b7c0be0 | ||
|
|
a49a5537d3 | ||
|
|
c407ad04bf | ||
|
|
480e0951b8 | ||
|
|
a06c5bb297 | ||
|
|
77a54792dd | ||
|
|
d0d49397ca | ||
|
|
b51abeabac | ||
|
|
f0e4f17ab8 | ||
|
|
205da33fe5 | ||
|
|
9aa78111be | ||
|
|
c3f93d4aae | ||
|
|
5a5c0d7179 | ||
|
|
ba57942b7d | ||
|
|
c782deb581 | ||
|
|
566edfcd7b | ||
|
|
c3cf38c330 | ||
|
|
4953a41330 | ||
|
|
7ff4ed640d | ||
|
|
898a13fcb5 | ||
|
|
3fdc370466 | ||
|
|
39055ad0d2 | ||
|
|
21e73c973a | ||
|
|
4d03976032 | ||
|
|
eb7587270f | ||
|
|
3ea88a2be0 | ||
|
|
55778ba0b5 | ||
|
|
5d3694abd3 | ||
|
|
21d9ba0182 | ||
|
|
27848feddd | ||
|
|
ce261eeb65 | ||
|
|
8de3ae5468 | ||
|
|
367d27d48f | ||
|
|
1a9b6ab2a5 | ||
|
|
323b8ee67d | ||
|
|
5b95e1d41f | ||
|
|
a272d8e253 | ||
|
|
79285ca12e | ||
|
|
f90f676faf | ||
|
|
3224d8823d | ||
|
|
1a03b98670 | ||
|
|
80f32bfeb4 | ||
|
|
1b4693b981 | ||
|
|
535b760dd7 | ||
|
|
14775f6503 | ||
|
|
a856d249c9 | ||
|
|
484b547df5 | ||
|
|
d73ca2c890 | ||
|
|
6211bd8c69 | ||
|
|
e638a471d1 | ||
|
|
42ee21e883 | ||
|
|
263af58dc0 | ||
|
|
6727c0655a | ||
|
|
cba249938a | ||
|
|
9fbed47617 | ||
|
|
b5dd722888 | ||
|
|
11bef52568 | ||
|
|
d22a369333 | ||
|
|
dfe95296d9 | ||
|
|
8d39893e5e | ||
|
|
b8b8a501e1 | ||
|
|
2a36f378b4 | ||
|
|
6746df37a1 | ||
|
|
364f66b7d4 | ||
|
|
84bbd93216 | ||
|
|
85ef8d7d50 | ||
|
|
2b6606d8ad | ||
|
|
4772a61e7c | ||
|
|
d30375f3c4 | ||
|
|
8c831ac0e9 | ||
|
|
1ede7028a5 | ||
|
|
5b8dd0a693 | ||
|
|
cc041510be | ||
|
|
05baec85b7 | ||
|
|
fb698fd029 | ||
|
|
bbfec136e8 | ||
|
|
36271a2c24 | ||
|
|
bbe1f133dc | ||
|
|
d7b0614556 | ||
|
|
7e9f27a613 | ||
|
|
3bdc97d4d5 | ||
|
|
8a7511a941 | ||
|
|
a9511e6a29 | ||
|
|
ac37ead419 | ||
|
|
39fcda59da | ||
|
|
9c44e104bb | ||
|
|
18f8db7942 | ||
|
|
71281bc82d | ||
|
|
0557def0b6 | ||
|
|
1a3f7fbbee | ||
|
|
7bed8bf84e | ||
|
|
790371a9e2 | ||
|
|
537cf19e97 | ||
|
|
35ad43b7b3 | ||
|
|
3d70e8c1e6 | ||
|
|
7bb30d37ce | ||
|
|
0267f00b48 | ||
|
|
5a7cec91c5 | ||
|
|
642bf63abc | ||
|
|
6f3197f482 | ||
|
|
5c88968879 | ||
|
|
c4a43183b3 | ||
|
|
94b583d7f3 | ||
|
|
37012e55e3 | ||
|
|
ea4d613d12 | ||
|
|
0e6108b5a9 | ||
|
|
fdbaf7509f | ||
|
|
74182031ae | ||
|
|
6c80a34578 | ||
|
|
09f1c13d28 | ||
|
|
5668fe13ae | ||
|
|
78a02b6d85 | ||
|
|
ccab932e8d | ||
|
|
eaea1f383b | ||
|
|
de8309de4a | ||
|
|
bc3269037f | ||
|
|
31131427b8 | ||
|
|
9957bff62b | ||
|
|
f1841347a7 | ||
|
|
1b8b72c443 | ||
|
|
b4affbff6d | ||
|
|
c8b4a38bb6 | ||
|
|
eec373e2ae | ||
|
|
48b261317d | ||
|
|
e6beb01075 | ||
|
|
ecc6e9286a | ||
|
|
179351cb6b | ||
|
|
778fe43012 | ||
|
|
d84d52df4b | ||
|
|
11d4109915 | ||
|
|
0eddbac150 | ||
|
|
99afeb221a | ||
|
|
39d18b78a1 | ||
|
|
4ebe8cc0cc | ||
|
|
6dabfb7fe2 | ||
|
|
611b1d9aca | ||
|
|
2821f8e750 | ||
|
|
1cccd8dc2c | ||
|
|
4d13982594 | ||
|
|
10c63640c0 | ||
|
|
14ad1239db | ||
|
|
2a16cb6e64 | ||
|
|
89fa5947bd | ||
|
|
a81e56e3bf | ||
|
|
90ad2dde54 | ||
|
|
9c243cbe8d | ||
|
|
c1b444541f | ||
|
|
8527b16e9d | ||
|
|
a728420010 | ||
|
|
378d9e8634 | ||
|
|
1973081529 | ||
|
|
45ae6d802c | ||
|
|
c4297e2996 | ||
|
|
310afe3ab8 | ||
|
|
3215f36530 | ||
|
|
55621e12d9 | ||
|
|
458dc516f4 | ||
|
|
f2ae84bd22 | ||
|
|
f093df1cb9 | ||
|
|
05f15f7876 | ||
|
|
12f4a74094 | ||
|
|
15d895fd0a | ||
|
|
1890948924 | ||
|
|
fec246127f | ||
|
|
ecab30d4ac | ||
|
|
f8cc688241 | ||
|
|
f51b3528d5 | ||
|
|
42c94a1017 | ||
|
|
acccb56f07 | ||
|
|
3a2d3ac985 | ||
|
|
0ab18e6e08 | ||
|
|
44db5991e7 | ||
|
|
15a6c50326 | ||
|
|
911aa40ca1 | ||
|
|
2b679daabc | ||
|
|
71b956e613 | ||
|
|
79089a93bc | ||
|
|
da3ac1794e | ||
|
|
bc870b2aa2 | ||
|
|
6bc40ce2e1 | ||
|
|
84544979fa | ||
|
|
2446e4d1fd | ||
|
|
4a15b39945 | ||
|
|
df080bbad9 | ||
|
|
8632af8820 | ||
|
|
27047c0f39 | ||
|
|
95de3e339d | ||
|
|
99f44aece5 | ||
|
|
4e589aecbf | ||
|
|
ab013554bd | ||
|
|
5c966e291b | ||
|
|
068744b681 | ||
|
|
8c794baa7b | ||
|
|
f6a23723f8 | ||
|
|
4b3cc2e3ec | ||
|
|
4ee743d309 | ||
|
|
d3b4bab40a | ||
|
|
c71b54fb5b | ||
|
|
ecbdf01bdf | ||
|
|
c2e8a6c73d | ||
|
|
29037d19fb | ||
|
|
67d242d210 | ||
|
|
91a67def99 | ||
|
|
c8ab89ef37 | ||
|
|
17a9b7eb0a | ||
|
|
cdb592d744 | ||
|
|
af19941a07 | ||
|
|
00dce83096 | ||
|
|
597e60d6f1 | ||
|
|
4e4311cac0 | ||
|
|
c11402195f | ||
|
|
31ec15811f | ||
|
|
739ac7b42e | ||
|
|
ad3049ab0a | ||
|
|
d96c3f3ed7 | ||
|
|
dcfd0d5b11 | ||
|
|
b05712cf83 | ||
|
|
df15485d7c | ||
|
|
bb15fcdc46 | ||
|
|
e34291fbd5 | ||
|
|
55b8c2d04c | ||
|
|
8bd1cd03b4 | ||
|
|
bafb7c35fb | ||
|
|
9425558ff7 | ||
|
|
f20aad3813 | ||
|
|
7a683d3637 | ||
|
|
ac982cbb15 | ||
|
|
9889b1b5c4 | ||
|
|
7cb647e5f1 | ||
|
|
515b75160c | ||
|
|
a365dc7519 | ||
|
|
764520714b | ||
|
|
43e087ae91 | ||
|
|
bffccc585a | ||
|
|
a01f10b042 | ||
|
|
26a5f98aae | ||
|
|
67280546af | ||
|
|
64058b0f61 | ||
|
|
d7b5c81b0e | ||
|
|
1d03056784 | ||
|
|
dd0ab8f962 | ||
|
|
02e8dba971 | ||
|
|
59878fb190 | ||
|
|
9ff0f83af9 | ||
|
|
e6f825371e | ||
|
|
45f3f23033 | ||
|
|
ffd27db208 | ||
|
|
a452d6131b | ||
|
|
0bc478f9d3 | ||
|
|
03ef981765 | ||
|
|
9ca9f25fd3 | ||
|
|
41122dddb2 | ||
|
|
1e0c94d007 | ||
|
|
3e42a7fb4c | ||
|
|
a8fcc1fb44 | ||
|
|
e43416019d | ||
|
|
9f467ecec1 | ||
|
|
273d87dbf1 | ||
|
|
befd21f8cb | ||
|
|
882e3bc1cd | ||
|
|
15e05c4abc | ||
|
|
748a2f5fcf | ||
|
|
37ba42faf8 | ||
|
|
19e343e517 | ||
|
|
8f39129bf8 | ||
|
|
9c3521caf2 | ||
|
|
40fc0fd2f9 | ||
|
|
ff8566498f | ||
|
|
dd06882860 | ||
|
|
fb2294c945 | ||
|
|
26ea8320ce | ||
|
|
0f4963d91e | ||
|
|
91020abc90 | ||
|
|
64906f3ea0 | ||
|
|
28f85b4c5a | ||
|
|
b44a0d6813 | ||
|
|
8af7cde2d6 | ||
|
|
3fcd656bb6 | ||
|
|
76c827257e | ||
|
|
8ca9f7ee30 | ||
|
|
da7a06646a | ||
|
|
0a36f1df7a | ||
|
|
80e5d30781 | ||
|
|
9c4beba3b1 | ||
|
|
0cf932f57e | ||
|
|
5cb9f3b014 | ||
|
|
3eb581142a | ||
|
|
d6c460e7fd | ||
|
|
a2baa50530 | ||
|
|
6569b8c038 | ||
|
|
48b4bf02a3 | ||
|
|
693054a92a | ||
|
|
1472e53410 | ||
|
|
5ed4970d62 | ||
|
|
056cf3cbd6 | ||
|
|
2bcd548747 | ||
|
|
9edcf47073 | ||
|
|
084d90e714 | ||
|
|
a738cc36dd | ||
|
|
9b6f9aeda3 | ||
|
|
8ea8c1821d | ||
|
|
53a1a8826e | ||
|
|
237551d9f6 | ||
|
|
f7c7bc65f2 | ||
|
|
badbd9c6fe | ||
|
|
cc7ac5b911 | ||
|
|
5957300c4e | ||
|
|
2e343ce0c3 | ||
|
|
3113a4be2b | ||
|
|
7d9cb2932f | ||
|
|
026c2caea0 | ||
|
|
eb058b688d | ||
|
|
2a7a0ce3f6 | ||
|
|
a330110eef | ||
|
|
feed534be5 | ||
|
|
2375633bca | ||
|
|
7018139289 | ||
|
|
5f67934f26 | ||
|
|
574cc8ad33 | ||
|
|
658c613c4e | ||
|
|
c2ce54c2a7 | ||
|
|
58da0d9778 | ||
|
|
8b90036c11 | ||
|
|
65678ea739 | ||
|
|
34ddc9b7ff | ||
|
|
97f9914d33 | ||
|
|
8b64851f6f | ||
|
|
c00f50238e | ||
|
|
25ea57e02f | ||
|
|
a951afe205 | ||
|
|
44c7954ce7 | ||
|
|
ef315b6dde | ||
|
|
935a9dcbb7 | ||
|
|
2bda432d70 | ||
|
|
d567ea3cf0 | ||
|
|
7b5e386595 | ||
|
|
1c65a7caba | ||
|
|
12ebacf1a7 | ||
|
|
f2c176111f | ||
|
|
cc242e5eba | ||
|
|
4888808ad0 | ||
|
|
cd1b5e1d57 | ||
|
|
9661c9a0eb | ||
|
|
f6ccf6da44 | ||
|
|
b691488240 | ||
|
|
eb71996e6a | ||
|
|
b9566ae1d6 | ||
|
|
8016fc4287 | ||
|
|
c95b43ea69 | ||
|
|
d767a503cd | ||
|
|
221131f9d3 | ||
|
|
f307cccabb | ||
|
|
2f21d0d94c | ||
|
|
132d1292ce | ||
|
|
df9a10cb53 | ||
|
|
95d564901b | ||
|
|
6424d9b1c0 | ||
|
|
38a3d20acf | ||
|
|
89b117bbc2 | ||
|
|
eeba7a3a6b | ||
|
|
23a660aabb | ||
|
|
c9bddba446 | ||
|
|
3a508a3ec4 | ||
|
|
6bf33f6447 | ||
|
|
a02054ceb6 | ||
|
|
8422521975 | ||
|
|
fbfacc5ed5 | ||
|
|
b9d96620a4 | ||
|
|
8c61735579 | ||
|
|
56e8ccdfc4 | ||
|
|
5454e7dd16 | ||
|
|
901a27140c | ||
|
|
37db2b9504 | ||
|
|
5e7768f912 | ||
|
|
80dd16740d | ||
|
|
24421a0224 | ||
|
|
26d26cf088 | ||
|
|
615c5e8439 | ||
|
|
090387ef37 | ||
|
|
25ea7d8b0c | ||
|
|
68f067f2c4 | ||
|
|
e20fa5ab39 | ||
|
|
bee307a91d | ||
|
|
f85226ce55 | ||
|
|
f112e6f6cc | ||
|
|
5df82b7e2c | ||
|
|
ea75a34c82 | ||
|
|
07d0de0151 | ||
|
|
0a75dd7e3c | ||
|
|
88afd3f453 | ||
|
|
9669a044ba | ||
|
|
e31ebab12b | ||
|
|
e68a3a0d3a | ||
|
|
4ae09c8766 | ||
|
|
a693e96248 | ||
|
|
60b0de79b3 | ||
|
|
86277396f7 | ||
|
|
0b65d55601 | ||
|
|
23782ec773 | ||
|
|
0b33497842 | ||
|
|
6cd4bcd41c | ||
|
|
8d8db3ba85 | ||
|
|
d9c2066035 | ||
|
|
af5cbf045d | ||
|
|
99d67cdd42 | ||
|
|
a74910ddf6 | ||
|
|
d9678d04dd | ||
|
|
c7acf89d84 | ||
|
|
24f1fe13cc | ||
|
|
11fcd8bcfe | ||
|
|
bcde5bad63 | ||
|
|
d2a8fbaf1e | ||
|
|
f9d2b18959 | ||
|
|
bdba2ae6e4 | ||
|
|
f068ed97f1 | ||
|
|
7ab2e782ac | ||
|
|
88a7d12306 | ||
|
|
dffe8b2648 | ||
|
|
daa98b106e | ||
|
|
83796341c5 | ||
|
|
ea24cd8a0f | ||
|
|
0e7ff32d02 | ||
|
|
31706bfc21 | ||
|
|
993e2fdc22 | ||
|
|
0d05cf489b | ||
|
|
0961b814d5 | ||
|
|
999c407f12 | ||
|
|
7c137d71ca | ||
|
|
ad26768d6d | ||
|
|
5ed7d60ae8 | ||
|
|
a67379fcb2 | ||
|
|
cccae3fbcc | ||
|
|
10d85c6547 | ||
|
|
21af1adefe | ||
|
|
fe02258a00 | ||
|
|
3d8ec8e295 | ||
|
|
d5b496aa67 | ||
|
|
8458cfc468 | ||
|
|
f10d2ef48d | ||
|
|
2ee433bb89 | ||
|
|
237cf91f5a | ||
|
|
8db7e4a5b9 | ||
|
|
a3703514b1 | ||
|
|
db8ed34dc4 | ||
|
|
21b89cf84d | ||
|
|
fc0f29337b | ||
|
|
84b9e6ae18 | ||
|
|
cbabaa7d91 | ||
|
|
4cfe704242 | ||
|
|
25cae61cc1 | ||
|
|
d96b3e6d05 | ||
|
|
1f261476d5 | ||
|
|
3171fc7375 | ||
|
|
ba843c1589 | ||
|
|
f7f01ea875 | ||
|
|
8ea1dfc7d2 | ||
|
|
9616a113b0 | ||
|
|
4aaf6e95cf | ||
|
|
edfdfb1016 | ||
|
|
3067149357 | ||
|
|
d5548c8bdc | ||
|
|
cf66dc99b4 | ||
|
|
891619fa26 | ||
|
|
1f6462be38 | ||
|
|
e74dc1fd78 | ||
|
|
f59768ce17 | ||
|
|
22d015615d | ||
|
|
0ef0ca8518 | ||
|
|
1917c5d7cb | ||
|
|
ff0fe593d3 | ||
|
|
12e8d64ec2 | ||
|
|
c0c13eb687 | ||
|
|
91b78f9a23 | ||
|
|
32474d10ce | ||
|
|
7c3de25c20 | ||
|
|
f75b7b1a59 | ||
|
|
a3e01b8a3b | ||
|
|
6c9a9b8632 | ||
|
|
3fba75868f | ||
|
|
8dee390d75 | ||
|
|
dc838639b2 | ||
|
|
3fd05c8eb7 | ||
|
|
5f0df140b0 | ||
|
|
b98cbd3ec5 | ||
|
|
18d67d088e | ||
|
|
0bf60394fe | ||
|
|
cec5ffd547 | ||
|
|
026ea4450e | ||
|
|
9a1dd5bb98 | ||
|
|
fbc42fbb15 | ||
|
|
5613cde00f | ||
|
|
d65d6f49cd | ||
|
|
c9bc18cf4b | ||
|
|
9179127bce | ||
|
|
16b6bef393 | ||
|
|
52159ac596 | ||
|
|
0dc3fd43e9 | ||
|
|
b0d490036f | ||
|
|
c28b098c65 | ||
|
|
4a6ccce09a | ||
|
|
5053ad08dd | ||
|
|
72b4809ed8 | ||
|
|
6799fe5189 | ||
|
|
12635ff4a5 | ||
|
|
5908fd9d9c | ||
|
|
5c07a2c0cc | ||
|
|
f5048abae7 | ||
|
|
76acffdb2e | ||
|
|
1ac96aa02e | ||
|
|
3386ac7f8a | ||
|
|
1e4c157c28 | ||
|
|
a1c5297eef | ||
|
|
cda04bef26 | ||
|
|
1edf60b617 | ||
|
|
32cf4dd6c9 | ||
|
|
f0caeb089d | ||
|
|
23f1e7569c | ||
|
|
5087fdb5d6 | ||
|
|
b654a42229 | ||
|
|
d312c8e592 | ||
|
|
319787bae3 | ||
|
|
d124b04a2c | ||
|
|
4ef8a3a163 | ||
|
|
41b5cdddf2 | ||
|
|
e10453b2fd | ||
|
|
d2f665ab70 | ||
|
|
4083478b65 | ||
|
|
01136a19a5 | ||
|
|
0b2df96461 | ||
|
|
f66c3ff322 | ||
|
|
5d8fe89e5a | ||
|
|
22eb5436ab | ||
|
|
17bdd87576 | ||
|
|
8f7c0a1d97 | ||
|
|
3b453b18bc | ||
|
|
a1fc5bf54b | ||
|
|
0cb413a579 | ||
|
|
d326d345f4 | ||
|
|
1de647e8a5 | ||
|
|
c562b88b32 | ||
|
|
f2e38330ea | ||
|
|
f2dca2a90a | ||
|
|
9f1cd04d45 | ||
|
|
fe67f3a982 | ||
|
|
2fd6e9ebf5 | ||
|
|
0f1195de82 | ||
|
|
267042f74f | ||
|
|
ea9783dbfc | ||
|
|
67655c4b06 | ||
|
|
2970aa5ba3 | ||
|
|
99a3ffcf17 | ||
|
|
9bc5bde3c2 | ||
|
|
0edb844225 | ||
|
|
e3feb8f11e | ||
|
|
6b7534b7fb | ||
|
|
ca1506de8b | ||
|
|
1cb535dea3 | ||
|
|
5d32b6d383 | ||
|
|
c203b8e6d2 | ||
|
|
e6dbe020c1 | ||
|
|
63cf1603b0 | ||
|
|
c184a0af10 | ||
|
|
8a4e6d5ed5 | ||
|
|
aadb67fa79 | ||
|
|
4949471518 | ||
|
|
9504723ef2 | ||
|
|
3abfb7bb9c | ||
|
|
3ef6bf8681 | ||
|
|
1647a10b1b | ||
|
|
55b893362c | ||
|
|
48f1928327 | ||
|
|
dc793f145d | ||
|
|
77e0b7d89c | ||
|
|
cec19860bc | ||
|
|
898acb90d0 | ||
|
|
a074ac732d | ||
|
|
c71526b95c | ||
|
|
f035e31dcf | ||
|
|
35192b9dde | ||
|
|
b5ac637231 | ||
|
|
4e0ef8b0e3 | ||
|
|
c32ee4dfb5 | ||
|
|
accfeab6fa | ||
|
|
d98f3cc8c5 | ||
|
|
342f238983 | ||
|
|
73f8ea0fc5 | ||
|
|
f2bd1ff575 | ||
|
|
b3ec23d6bd | ||
|
|
1fc7fa4720 | ||
|
|
58ae058465 | ||
|
|
7ece395d1b | ||
|
|
4bb876031e | ||
|
|
e4f129db04 | ||
|
|
90038e08dc | ||
|
|
4c30e930cf | ||
|
|
dd69e02f6b | ||
|
|
f2ccf1953d | ||
|
|
0e133840c9 | ||
|
|
e12b277472 | ||
|
|
dc7b1809c1 | ||
|
|
8c2146ff55 | ||
|
|
882d412409 | ||
|
|
3f88a9469c | ||
|
|
3ac7d43a81 | ||
|
|
d12446b6d9 | ||
|
|
865fb3a967 | ||
|
|
48538222b2 | ||
|
|
8d44f61517 | ||
|
|
0e4f6f4209 | ||
|
|
a2823563bf | ||
|
|
353cdb324d | ||
|
|
216f799db1 | ||
|
|
4d6f080263 | ||
|
|
b9d124618c | ||
|
|
ab5d9e8d36 | ||
|
|
4cdeecd952 | ||
|
|
59b3933cb6 | ||
|
|
179ddcb348 | ||
|
|
efa2c8fc4b | ||
|
|
c958c7d61a | ||
|
|
35fca9c450 | ||
|
|
61962fbc07 | ||
|
|
39e724befe | ||
|
|
43bb77b095 | ||
|
|
28e1e46586 | ||
|
|
2f5b879652 | ||
|
|
16930fe8ca | ||
|
|
1db1b6e524 | ||
|
|
43eba7a010 | ||
|
|
49278bdea4 | ||
|
|
2405e11af2 | ||
|
|
23b6894484 | ||
|
|
a837c9398c | ||
|
|
ea484e15f9 | ||
|
|
cce99a8b1d | ||
|
|
f29faafd78 | ||
|
|
c3eafbcd85 | ||
|
|
65e18ab4e2 | ||
|
|
8bb16ed3a7 | ||
|
|
e685284f72 | ||
|
|
86d2805642 | ||
|
|
29b98a15a4 | ||
|
|
ba9df92b12 | ||
|
|
0eac1c9bf9 | ||
|
|
515feb9f9e | ||
|
|
0b84b79e1d | ||
|
|
8fd129f4fe | ||
|
|
ba334930fe | ||
|
|
982d64ddca | ||
|
|
3577300361 | ||
|
|
0478e0ff7c | ||
|
|
c2cfd0a1b0 | ||
|
|
637ba30df1 | ||
|
|
fa8421b297 | ||
|
|
61c23a57d9 | ||
|
|
43f61fd2df | ||
|
|
85eed64fe9 | ||
|
|
43634a4312 | ||
|
|
9757db4438 | ||
|
|
17a2ba7f1a | ||
|
|
03c7417888 | ||
|
|
2b2c86ba5a | ||
|
|
2b2217e8ce | ||
|
|
08d3e8bab6 | ||
|
|
ded3552873 | ||
|
|
9a7893e99f | ||
|
|
307ef4e285 | ||
|
|
99b43b0379 | ||
|
|
6fb8fbba18 | ||
|
|
09c750e622 | ||
|
|
f75deb3505 | ||
|
|
6281f9cfe1 | ||
|
|
b4f174f2f4 | ||
|
|
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 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,7 +22,7 @@ _Make sure your have performed every step and checked the applicable boxes befor
|
|||||||
- [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues)
|
- [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues)
|
||||||
- [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
|
- [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
|
||||||
- [ ] Searched the issue in the [docs](https://emsesp.org/Troubleshooting/)
|
- [ ] Searched the issue in the [docs](https://emsesp.org/Troubleshooting/)
|
||||||
- [ ] Searched the issue in the [chat](https://discord.gg/3J3GgnzpyT)
|
- [ ] Searched the issue in the [chat](https://discord.gg/GP9DPSgeJq)
|
||||||
- [ ] Provide the System information in the area below, taken from `http://<IP>/api/system`
|
- [ ] Provide the System information in the area below, taken from `http://<IP>/api/system`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,5 +7,5 @@ contact_links:
|
|||||||
url: https://github.com/emsesp/EMS-ESP32/discussions
|
url: https://github.com/emsesp/EMS-ESP32/discussions
|
||||||
about: EMS-ESP usage Questions, Feature Requests and Projects.
|
about: EMS-ESP usage Questions, Feature Requests and Projects.
|
||||||
- name: EMS-ESP Users Chat
|
- name: EMS-ESP Users Chat
|
||||||
url: https://discord.gg/3J3GgnzpyT
|
url: https://discord.gg/GP9DPSgeJq
|
||||||
about: Chat for feedback, questions and troubleshooting.
|
about: Chat for feedback, questions and troubleshooting.
|
||||||
|
|||||||
8
.github/workflows/dev_release.yml
vendored
8
.github/workflows/dev_release.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
node-version: 24
|
node-version: 24
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Enable Corepack
|
||||||
run: corepack enable pnpm
|
run: corepack enable pnpm
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build webUI
|
- name: Build webUI
|
||||||
run: |
|
run: |
|
||||||
platformio run -e build_webUI
|
platformio run -e build-webUI
|
||||||
|
|
||||||
- name: Build modbus
|
- name: Build modbus
|
||||||
run: |
|
run: |
|
||||||
@@ -62,13 +62,13 @@ jobs:
|
|||||||
platformio run
|
platformio run
|
||||||
|
|
||||||
- name: Commit the generated files
|
- name: Commit the generated files
|
||||||
uses: stefanzweifel/git-auto-commit-action@v5
|
uses: stefanzweifel/git-auto-commit-action@v7
|
||||||
with:
|
with:
|
||||||
commit_message: "chore: update generated files for v${{steps.build_info.outputs.VERSION}}"
|
commit_message: "chore: update generated files for v${{steps.build_info.outputs.VERSION}}"
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
id: 'automatic_releases'
|
id: 'automatic_releases'
|
||||||
uses: emsesp/action-automatic-releases@v1.0.0
|
uses: emsesp/action-automatic-releases@v1.0.1
|
||||||
with:
|
with:
|
||||||
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
title: Development Build v${{steps.build_info.outputs.VERSION}}
|
title: Development Build v${{steps.build_info.outputs.VERSION}}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: GitHub Releases To Discord
|
- name: GitHub Releases To Discord
|
||||||
uses: SethCohen/github-releases-to-discord@v1.13.1
|
uses: SethCohen/github-releases-to-discord@v1.13.1
|
||||||
|
|||||||
2
.github/workflows/pr_check.yml
vendored
2
.github/workflows/pr_check.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install python 3.13
|
- name: Install python 3.13
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
|
|||||||
2
.github/workflows/sonar_check.yml
vendored
2
.github/workflows/sonar_check.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
BUILD_WRAPPER_OUT_DIR: bw-output
|
BUILD_WRAPPER_OUT_DIR: bw-output
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Build Wrapper
|
- name: Install Build Wrapper
|
||||||
|
|||||||
6
.github/workflows/stable_release.yml
vendored
6
.github/workflows/stable_release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
node-version: 24
|
node-version: 24
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Enable Corepack
|
||||||
run: corepack enable pnpm
|
run: corepack enable pnpm
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build webUI
|
- name: Build webUI
|
||||||
run: |
|
run: |
|
||||||
platformio run -e build_webUI
|
platformio run -e build-webUI
|
||||||
|
|
||||||
- name: Build modbus
|
- name: Build modbus
|
||||||
run: |
|
run: |
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
platformio run
|
platformio run
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
uses: emsesp/action-automatic-releases@v1.0.0
|
uses: emsesp/action-automatic-releases@v1.0.1
|
||||||
with:
|
with:
|
||||||
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|||||||
6
.github/workflows/test_release.yml
vendored
6
.github/workflows/test_release.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
node-version: 24
|
node-version: 24
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable Corepack
|
- name: Enable Corepack
|
||||||
run: corepack enable pnpm
|
run: corepack enable pnpm
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build webUI
|
- name: Build webUI
|
||||||
run: |
|
run: |
|
||||||
platformio run -e build_webUI
|
platformio run -e build-webUI
|
||||||
|
|
||||||
- name: Build modbus
|
- name: Build modbus
|
||||||
run: |
|
run: |
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
id: 'automatic_releases'
|
id: 'automatic_releases'
|
||||||
uses: emsesp/action-automatic-releases@v1.0.0
|
uses: emsesp/action-automatic-releases@v1.0.1
|
||||||
with:
|
with:
|
||||||
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
repo_token: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
title: Test Build v${{steps.build_info.outputs.VERSION}}
|
title: Test Build v${{steps.build_info.outputs.VERSION}}
|
||||||
|
|||||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -5,7 +5,36 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [3.8.0]
|
## [3.8.1] 11 January 2026
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- update time saved in nvs
|
||||||
|
- heatpump entities [#2883](https://github.com/emsesp/EMS-ESP32/issues/2883)
|
||||||
|
- HA input number format (mode) selectable box/slider (slider for max range 100) [#2900](https://github.com/emsesp/EMS-ESP32/discussions/2900)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- fix EMS bus disconnected errors on some systems [#2881](https://github.com/emsesp/EMS-ESP32/issues/2881)
|
||||||
|
- selflowtemp fix [#2876](https://github.com/emsesp/EMS-ESP32/issues/2876)
|
||||||
|
- updated valid GPIOs for ESP32S2, ESP32S3 and ESP32 that caused custom systems to block gpios [#2887](https://github.com/emsesp/EMS-ESP32/issues/2887)
|
||||||
|
- Junkers wwcharge offset [#2860](https://github.com/emsesp/EMS-ESP32/issues/2860)
|
||||||
|
- fixed minflowtemp [#2890](https://github.com/emsesp/EMS-ESP32/issues/2890)
|
||||||
|
- don't add HA uom/classes for bool values [#2885](https://github.com/emsesp/EMS-ESP32/issues/2885)
|
||||||
|
- fixed missing progress bar on web firmware uploads
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- snapshot gpios stored in temporary ram
|
||||||
|
- GPIOs stored along with the name and reported in log if conflicting
|
||||||
|
- free GPIOs depend on board profile [#2901](https://github.com/emsesp/EMS-ESP32/issues/2901)
|
||||||
|
- prefer PSram for mqtt queue [#2889](https://github.com/emsesp/EMS-ESP32/issues/2889)
|
||||||
|
- day schedule defult to all days, no day selected is not allowed
|
||||||
|
- board profile `CUSTOM` can only be selected in developer mode
|
||||||
|
- mqtt sends round values without decimals (`28` instead of `28.0`)
|
||||||
|
|
||||||
|
|
||||||
|
## [3.8.0] 31 December 2025
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
@@ -26,8 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610)
|
- 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)
|
- CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437)
|
||||||
- implemented eFuse settings for BBQKees boards to store model type and ESP chipset
|
- implemented eFuse settings for BBQKees boards to store model type and ESP chipset
|
||||||
- Analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624)
|
- 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)
|
- analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631)
|
||||||
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636)
|
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636)
|
||||||
- Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645)
|
- Greenstar 2000 [#2645](https://github.com/emsesp/EMS-ESP32/issues/2645)
|
||||||
- RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659)
|
- RC3xx `dhw modetype` [#2659](https://github.com/emsesp/EMS-ESP32/discussions/2659)
|
||||||
@@ -90,7 +119,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- added Home Assistant device details to MQTT Discovery for all devices
|
- added Home Assistant device details to MQTT Discovery for all devices
|
||||||
- device_class and state_class changes for HA MQTT Discovery [#2825](https://github.com/emsesp/EMS-ESP32/issues/2825)
|
- device_class and state_class changes for HA MQTT Discovery [#2825](https://github.com/emsesp/EMS-ESP32/issues/2825)
|
||||||
|
|
||||||
|
|
||||||
## [3.7.2] 22 March 2025
|
## [3.7.2] 22 March 2025
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|||||||
@@ -1,3 +1,39 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
For more details go to [emsesp.org](https://emsesp.org/).
|
For more details go to [emsesp.org](https://emsesp.org/).
|
||||||
|
|
||||||
|
## [3.8.2]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
|
||||||
|
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
|
||||||
|
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
|
||||||
|
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||||
|
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
||||||
|
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||||
|
- e-mail notification using ReadyMail Client
|
||||||
|
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
|
||||||
|
- full system backup and restore
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
|
||||||
|
- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
|
||||||
|
- custom entities check fetch length
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- weblogbuffer up to 1000 messages with PSRAM, mentioned in [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||||
|
- validate custom entity writes, [#2931](https://github.com/emsesp/EMS-ESP32/issues/2931)
|
||||||
|
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
|
||||||
|
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
|
||||||
|
- translated modes `heat` and `eco` for HA-climate mode-str-tpl
|
||||||
|
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
||||||
|
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
||||||
|
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
||||||
|
- use tasmota core 2026.03.30
|
||||||
|
- secure mqtt uses ESP_SSLClient
|
||||||
|
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
|
||||||
|
- move http client from stack to heap
|
||||||
|
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -47,27 +47,28 @@ MAKEFLAGS += -j$(JOBS) -l$(shell echo $$(($(JOBS) * 2)))
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
TARGET := emsesp
|
TARGET := emsesp
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := src/core src/devices src/web src/test lib_standalone lib/semver lib/espMqttClient/src lib/espMqttClient/src/* lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/PButton
|
SOURCES := src/core src/devices src/web src/test lib_standalone lib/espMqttClient/src lib/espMqttClient/src/* lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/PButton
|
||||||
INCLUDES := src/core src/devices src/web src/test lib_standalone lib/* lib/semver lib/espMqttClient/src lib/espMqttClient/src/Transport lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src
|
INCLUDES := src/core src/devices src/web src/test lib_standalone lib/* lib/espMqttClient/src lib/espMqttClient/src/Transport lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src
|
||||||
LIBRARIES :=
|
LIBRARIES :=
|
||||||
|
|
||||||
CPPCHECK = cppcheck
|
CPPCHECK = cppcheck
|
||||||
CHECKFLAGS = -q --force --std=gnu++17
|
CHECKFLAGS = -q --force --std=gnu++20
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Languages Standard
|
# Languages Standard
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
C_STANDARD := -std=c17
|
C_STANDARD := -std=c20
|
||||||
CXX_STANDARD := -std=gnu++17
|
CXX_STANDARD := -std=gnu++20
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Defined Symbols
|
# Defined Symbols
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
||||||
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
|
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
|
||||||
|
DEFINES += -DNO_TLS_SUPPORT
|
||||||
DEFINES += $(ARGS)
|
DEFINES += $(ARGS)
|
||||||
|
|
||||||
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
|
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
@@ -79,6 +80,10 @@ SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
|
|||||||
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
|
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
|
||||||
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
|
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
|
||||||
|
|
||||||
|
# Exclude files not needed for standalone build, if they exist
|
||||||
|
CSOURCES := $(filter-out src/core/ModuleLibrary.c,$(CSOURCES))
|
||||||
|
CXXSOURCES := $(filter-out src/core/ModuleLibrary.cpp,$(CXXSOURCES))
|
||||||
|
|
||||||
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||||
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||||
|
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -18,7 +18,7 @@
|
|||||||
<a href="https://emsesp.org">
|
<a href="https://emsesp.org">
|
||||||
<img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" />
|
<img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.gg/3J3GgnzpyT">
|
<a href="https://discord.gg/GP9DPSgeJq">
|
||||||
<img src="https://img.shields.io/badge/Discord-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
|
<img src="https://img.shields.io/badge/Discord-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md">
|
<a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md">
|
||||||
@@ -32,7 +32,8 @@
|
|||||||
[](https://sonarcloud.io/summary/new_code?id=emsesp_EMS-ESP32)
|
[](https://sonarcloud.io/summary/new_code?id=emsesp_EMS-ESP32)
|
||||||
[](https://app.codacy.com/gh/emsesp/EMS-ESP32/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
[](https://app.codacy.com/gh/emsesp/EMS-ESP32/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
||||||
[](https://github.com/emsesp/EMS-ESP32/releases)
|
[](https://github.com/emsesp/EMS-ESP32/releases)
|
||||||
[](https://discord.gg/3J3GgnzpyT)
|
[](https://discord.gg/GP9DPSgeJq)
|
||||||
|
[](https://deepwiki.com/emsesp/EMS-ESP32)
|
||||||
|
|
||||||
[](https://github.com/emsesp/EMS-ESP32/stargazers)
|
[](https://github.com/emsesp/EMS-ESP32/stargazers)
|
||||||
[](https://github.com/emsesp/EMS-ESP32/network)
|
[](https://github.com/emsesp/EMS-ESP32/network)
|
||||||
@@ -40,7 +41,8 @@
|
|||||||
|
|
||||||
**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.
|
||||||
|
|
||||||
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl> or custom built.
|
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl>. These gateways are tested thoroughly and certified to work with EMS-ESP.
|
||||||
|
|
||||||
|
|
||||||
## 📦 **Key Features**
|
## 📦 **Key Features**
|
||||||
|
|
||||||
@@ -64,29 +66,27 @@ Head over to the [Installation Guide](https://emsesp.org/Installing) section of
|
|||||||
|
|
||||||
## 📋 **Documentation**
|
## 📋 **Documentation**
|
||||||
|
|
||||||
Visit [emsesp.org](https://emsesp.org) for more details on how to install and configure EMS-ESP. There is also a collection of Frequently Asked Questions and Troubleshooting tips with example customizations from the community.
|
Visit [emsesp.org](https://emsesp.org) for more details on how to setup and configure EMS-ESP. You'll also find more a collection of example configuarations, Frequently Asked Questions and Troubleshooting tips.
|
||||||
|
|
||||||
## 💬 **Getting Support**
|
## 💬 **Getting Support**
|
||||||
|
|
||||||
To chat with the community reach out on our [Discord Server](https://discord.gg/3J3GgnzpyT).
|
To chat with the community reach out on our [Discord Server](https://discord.gg/GP9DPSgeJq).
|
||||||
|
|
||||||
If you find an issue or have a request, see [how to request support](https://emsesp.org/Support/) on how to submit a bug report or feature request.
|
If you find an issue or have a request, see the [Getting Support](https://emsesp.org/Support/) section of the documentation. Note if you are using a non-BBQKees EMS gateway, you may need to contact the manufacturer for support.
|
||||||
|
|
||||||
## 🎥 **Live Demo**
|
## 🎥 **Live Demo**
|
||||||
|
|
||||||
For a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language from the sign on page and log in with any username or password. Note not all features are operational as it's based on static data.
|
To see a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language and use any username and password to log in. Note whast you're seeing is static example data so not all features are operational.
|
||||||
|
|
||||||
## 💖 **Contributors**
|
## 💖 **Contributors**
|
||||||
|
|
||||||
EMS-ESP is a project created by [proddy](https://github.com/proddy) and owned and maintained by both [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP) with support from [BBQKees Electronics](https://bbqkees-electronics.nl).
|
EMS-ESP is a project originally created by [proddy](https://github.com/proddy) and maintained by the ems-esp community.
|
||||||
|
|
||||||
If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated.
|
If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated.
|
||||||
|
|
||||||
## 📦 **Building**
|
## 📦 **Building**
|
||||||
|
|
||||||
To build the web interface only, run `platformio run -e build_webUI`. This will install the necessary dependencies and build the web interface and also create the embedded code used need to build the firmware. You can run the web interface locally by going to the `interface` directory and running `pnpm standalone`.
|
See the [Building the firmware](https://emsesp.org/Building) guide in the documentation for instructions on how to build EMS-ESP from this source code.
|
||||||
|
|
||||||
To build the firmware, run `platformio run`. This will build the firmware for all ESP32 modules and place the binaries in the `build/firmware` folder. If you want to configure the build for a single platform create a local `pio_local.ni` file in the root directory (see example in `pio_local.ini_example`).
|
|
||||||
|
|
||||||
## 📢 **Libraries used**
|
## 📢 **Libraries used**
|
||||||
|
|
||||||
|
|||||||
5
SECURITY.md
Normal file
5
SECURITY.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Please report any security vulnerabilities using the [Contact Form](https://emsesp.org/About/#-contact).
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
},
|
},
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
"-DTASMOTA_SDK",
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_LOLIN_C3_MINI",
|
"-DARDUINO_LOLIN_C3_MINI",
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=1",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
"-DBOARD_HAS_PSRAM",
|
"-DBOARD_HAS_PSRAM",
|
||||||
"-DTASMOTA_SDK",
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
"-DARDUINO_USB_MODE=0"
|
"-DARDUINO_USB_MODE=0"
|
||||||
],
|
],
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
"flash_size": "4MB",
|
"flash_size": "4MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
"maximum_size": 4194304,
|
"maximum_size": 4194304,
|
||||||
"use_1200bps_touch": true,
|
"use_1200bps_touch": false,
|
||||||
"wait_for_upload_port": true,
|
"wait_for_upload_port": false,
|
||||||
"require_upload_port": true,
|
"require_upload_port": true,
|
||||||
"speed": 921600
|
"speed": 921600
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "32MB",
|
"flash_size": "32MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": "-DTASMOTA_SDK",
|
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "40000000L",
|
"f_flash": "40000000L",
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "16MB",
|
"flash_size": "16MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"arduino",
|
"arduino",
|
||||||
"espidf"
|
"espidf"
|
||||||
],
|
],
|
||||||
"name": "Espressif ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
"name": "Tasmota ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
|
||||||
"upload": {
|
"upload": {
|
||||||
"flash_size": "16MB",
|
"flash_size": "16MB",
|
||||||
"maximum_ram_size": 327680,
|
"maximum_ram_size": 327680,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": "-DTASMOTA_SDK",
|
"extra_flags": "-DNO_TLS_SUPPORT",
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "40000000L",
|
"f_flash": "40000000L",
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
|
"-DNO_TLS_SUPPORT",
|
||||||
"-DARDUINO_XIAO_ESP32C6",
|
"-DARDUINO_XIAO_ESP32C6",
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=1",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dictionaries": ["project-words"],
|
"dictionaries": ["project-words"],
|
||||||
|
"caseSensitive": false,
|
||||||
"ignorePaths": [
|
"ignorePaths": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"compile_commands.json",
|
"compile_commands.json",
|
||||||
@@ -35,6 +36,9 @@
|
|||||||
"managed_components/**",
|
"managed_components/**",
|
||||||
"pnpm-*.yaml",
|
"pnpm-*.yaml",
|
||||||
"vite.config.ts",
|
"vite.config.ts",
|
||||||
"lib/esp32-psram/**"
|
"lib/esp32-psram/**",
|
||||||
|
"test/test_api/test_api.h",
|
||||||
|
"lib_standalone/**",
|
||||||
|
"**/*.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
{
|
{
|
||||||
|
"type": "systembackup",
|
||||||
|
"version": "3.8.2",
|
||||||
|
"date": "2026-03-29T13:28:15",
|
||||||
|
"systembackup": [
|
||||||
|
{
|
||||||
"type": "settings",
|
"type": "settings",
|
||||||
"Network": {
|
"Network": {
|
||||||
"ssid": "my_wifi_ssid",
|
"ssid": "",
|
||||||
"bssid": "",
|
"bssid": "",
|
||||||
"password": "my_wifi_password",
|
"password": "",
|
||||||
"hostname": "ems-esp"
|
"hostname": "ems-esp",
|
||||||
|
"static_ip_config": false,
|
||||||
|
"bandwidth20": false,
|
||||||
|
"nosleep": true,
|
||||||
|
"enableMDNS": true,
|
||||||
|
"enableCORS": false,
|
||||||
|
"CORSOrigin": "*",
|
||||||
|
"tx_power": 0
|
||||||
},
|
},
|
||||||
"AP": {
|
"AP": {
|
||||||
"provision_mode": 2,
|
"provision_mode": 2,
|
||||||
@@ -21,12 +33,14 @@
|
|||||||
"enableTLS": false,
|
"enableTLS": false,
|
||||||
"rootCA": "",
|
"rootCA": "",
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"host": "127.0.0.1",
|
"host": "",
|
||||||
"port": 1883,
|
"port": 1883,
|
||||||
"base": "ems-esp",
|
"base": "ems-esp",
|
||||||
"username": "username",
|
"username": "",
|
||||||
"password": "password",
|
"password": "",
|
||||||
"client_id": "ems-esp",
|
"client_id": "esp32-b8ffc9ec",
|
||||||
|
"keep_alive": 60,
|
||||||
|
"clean_session": false,
|
||||||
"entity_format": 1,
|
"entity_format": 1,
|
||||||
"publish_time_boiler": 10,
|
"publish_time_boiler": 10,
|
||||||
"publish_time_thermostat": 10,
|
"publish_time_thermostat": 10,
|
||||||
@@ -42,6 +56,7 @@
|
|||||||
"nested_format": 1,
|
"nested_format": 1,
|
||||||
"discovery_prefix": "homeassistant",
|
"discovery_prefix": "homeassistant",
|
||||||
"discovery_type": 0,
|
"discovery_type": 0,
|
||||||
|
"ha_number_mode": 0,
|
||||||
"publish_single": false,
|
"publish_single": false,
|
||||||
"publish_single2cmd": false,
|
"publish_single2cmd": false,
|
||||||
"send_response": false
|
"send_response": false
|
||||||
@@ -68,18 +83,146 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Settings": {
|
"Settings": {
|
||||||
"board_profile": "S3",
|
"version": "3.8.2",
|
||||||
|
"board_profile": "E32V2_2",
|
||||||
|
"platform": "ESP32",
|
||||||
"locale": "en",
|
"locale": "en",
|
||||||
"tx_mode": 1,
|
"tx_mode": 1,
|
||||||
"ems_bus_id": 11,
|
"ems_bus_id": 11,
|
||||||
|
"syslog_enabled": false,
|
||||||
|
"syslog_level": 3,
|
||||||
|
"trace_raw": false,
|
||||||
|
"syslog_mark_interval": 0,
|
||||||
|
"syslog_host": "",
|
||||||
|
"syslog_port": 514,
|
||||||
"boiler_heatingoff": false,
|
"boiler_heatingoff": false,
|
||||||
"hide_led": true,
|
"remote_timeout": 24,
|
||||||
|
"remote_timeout_en": false,
|
||||||
|
"shower_timer": false,
|
||||||
|
"shower_alert": false,
|
||||||
|
"shower_alert_coldshot": 10,
|
||||||
|
"shower_alert_trigger": 7,
|
||||||
|
"shower_min_duration": 180,
|
||||||
|
"rx_gpio": 4,
|
||||||
|
"tx_gpio": 5,
|
||||||
|
"dallas_gpio": 14,
|
||||||
|
"dallas_parasite": false,
|
||||||
|
"led_gpio": 32,
|
||||||
|
"hide_led": false,
|
||||||
|
"led_type": 1,
|
||||||
|
"low_clock": false,
|
||||||
"telnet_enabled": true,
|
"telnet_enabled": true,
|
||||||
"notoken_api": false,
|
"notoken_api": false,
|
||||||
|
"readonly_mode": false,
|
||||||
"analog_enabled": true,
|
"analog_enabled": true,
|
||||||
|
"pbutton_gpio": 34,
|
||||||
|
"solar_maxflow": 30,
|
||||||
"fahrenheit": false,
|
"fahrenheit": false,
|
||||||
"bool_format": 1,
|
"bool_format": 1,
|
||||||
"bool_dashboard": 1,
|
"bool_dashboard": 1,
|
||||||
"enum_format": 1
|
"enum_format": 1,
|
||||||
|
"weblog_level": 6,
|
||||||
|
"weblog_buffer": 50,
|
||||||
|
"weblog_compact": true,
|
||||||
|
"phy_type": 1,
|
||||||
|
"eth_power": 15,
|
||||||
|
"eth_phy_addr": 0,
|
||||||
|
"eth_clock_mode": 1,
|
||||||
|
"modbus_enabled": false,
|
||||||
|
"modbus_port": 502,
|
||||||
|
"modbus_max_clients": 10,
|
||||||
|
"modbus_timeout": 300,
|
||||||
|
"developer_mode": true,
|
||||||
|
"email_enabled": false,
|
||||||
|
"email_ssl": false,
|
||||||
|
"email_starttls": true,
|
||||||
|
"email_server": "smtp.example.net",
|
||||||
|
"email_port": 587,
|
||||||
|
"email_login": "",
|
||||||
|
"email_pass": "",
|
||||||
|
"email_sender": "ems-esp@example.net",
|
||||||
|
"email_recp": "",
|
||||||
|
"email_subject": "ems-esp notification"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "schedule",
|
||||||
|
"Schedule": {
|
||||||
|
"schedule": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "customizations",
|
||||||
|
"Customizations": {
|
||||||
|
"ts": [
|
||||||
|
{
|
||||||
|
"id": "28_1767_7B13_2502",
|
||||||
|
"name": "gateway_temperature",
|
||||||
|
"offset": 0,
|
||||||
|
"is_system": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"as": [
|
||||||
|
{
|
||||||
|
"gpio": 39,
|
||||||
|
"name": "core_voltage",
|
||||||
|
"offset": 0,
|
||||||
|
"factor": 0.003771,
|
||||||
|
"uom": 23,
|
||||||
|
"type": 3,
|
||||||
|
"is_system": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gpio": 36,
|
||||||
|
"name": "supply_voltage",
|
||||||
|
"offset": 0,
|
||||||
|
"factor": 0.017,
|
||||||
|
"uom": 23,
|
||||||
|
"type": 3,
|
||||||
|
"is_system": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gpio": 2,
|
||||||
|
"name": "led",
|
||||||
|
"offset": 0,
|
||||||
|
"factor": 1,
|
||||||
|
"uom": 0,
|
||||||
|
"type": 6,
|
||||||
|
"is_system": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"masked_entities": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "entities",
|
||||||
|
"Entities": {
|
||||||
|
"entities": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "modules",
|
||||||
|
"Modules": {
|
||||||
|
"modules": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "customSupport",
|
||||||
|
"Support": {
|
||||||
|
"html": [
|
||||||
|
"This product is installed and managed by:",
|
||||||
|
"",
|
||||||
|
"<b>Bosch Installer Example</b>",
|
||||||
|
"",
|
||||||
|
"Nefit Road 12",
|
||||||
|
"1234 AB Amsterdam",
|
||||||
|
"Phone: +31 123 456 789",
|
||||||
|
"email: support@boschinstaller.nl",
|
||||||
|
"",
|
||||||
|
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer."
|
||||||
|
],
|
||||||
|
"img_url": "https://emsesp.org/media/images/designer.png"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ telegram_type_id,name,is_fetched
|
|||||||
0x19,UBAMonitorSlow,
|
0x19,UBAMonitorSlow,
|
||||||
0x1A,UBASetPoints,
|
0x1A,UBASetPoints,
|
||||||
0x1C,UBAMaintenanceStatus,
|
0x1C,UBAMaintenanceStatus,
|
||||||
0x1E,WM10TempMessage,
|
0x1E,HydrTemp,
|
||||||
0x23,JunkersSetMixer,fetched
|
0x23,JunkersSetMixer,fetched
|
||||||
0x27,UBASettingsWW,fetched
|
0x27,UBASettingsWW,fetched
|
||||||
0x28,WeatherComp,fetched
|
0x28,WeatherComp,fetched
|
||||||
@@ -72,11 +72,12 @@ telegram_type_id,name,is_fetched
|
|||||||
0xE6,UBAParametersPlus,fetched
|
0xE6,UBAParametersPlus,fetched
|
||||||
0xE9,UBAMonitorWWPlus,
|
0xE9,UBAMonitorWWPlus,
|
||||||
0xEA,UBAParameterWWPlus,fetched
|
0xEA,UBAParameterWWPlus,fetched
|
||||||
|
0xEB,PumpKick,fetched
|
||||||
0x0101,ISM1Set,fetched
|
0x0101,ISM1Set,fetched
|
||||||
0x0103,ISM1StatusMessage,fetched
|
0x0103,ISM1StatusMessage,fetched
|
||||||
0x0104,ISM2StatusMessage,
|
0x0104,ISM2StatusMessage,
|
||||||
0x010C,IPMStatusMessage,
|
0x010C,IPMStatusMessage,
|
||||||
0x011E,JunkersDisp,fetched
|
0x011E,IPMTempMessage,
|
||||||
0x012E,HPEnergy1,
|
0x012E,HPEnergy1,
|
||||||
0x013B,HPEnergy2,
|
0x013B,HPEnergy2,
|
||||||
0x0165,JunkersSet,
|
0x0165,JunkersSet,
|
||||||
@@ -112,9 +113,9 @@ telegram_type_id,name,is_fetched
|
|||||||
0x02A1,RC300Curves,
|
0x02A1,RC300Curves,
|
||||||
0x02A2,RC300Curves,
|
0x02A2,RC300Curves,
|
||||||
0x02A5,RC300Monitor,fetched
|
0x02A5,RC300Monitor,fetched
|
||||||
0x02A6,RC300Monitor,
|
0x02A6,CRFMonitor,
|
||||||
0x02A7,RC300Monitor,
|
0x02A7,RC300Monitor,
|
||||||
0x02A8,RC300Monitor,
|
0x02A8,CRFMonitor,
|
||||||
0x02A9,RC300Monitor,
|
0x02A9,RC300Monitor,
|
||||||
0x02AA,RC300Monitor,
|
0x02AA,RC300Monitor,
|
||||||
0x02AB,RC300Monitor,
|
0x02AB,RC300Monitor,
|
||||||
@@ -197,7 +198,7 @@ telegram_type_id,name,is_fetched
|
|||||||
0x04A2,HpInput,fetched
|
0x04A2,HpInput,fetched
|
||||||
0x04A5,HPFan,fetched
|
0x04A5,HPFan,fetched
|
||||||
0x04A7,HPPowerLimit,fetched
|
0x04A7,HPPowerLimit,fetched
|
||||||
0x04AA,HPPower2,fetched
|
0x04AA,HPPower,
|
||||||
0x04AE,HPEnergy,fetched
|
0x04AE,HPEnergy,fetched
|
||||||
0x04AF,HPMeters,fetched
|
0x04AF,HPMeters,fetched
|
||||||
0x055C,VentilationSet,fetched
|
0x055C,VentilationSet,fetched
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"adapter": "react",
|
"adapter": "react",
|
||||||
"baseLocale": "pl",
|
"baseLocale": "pl",
|
||||||
"$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
|
"$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import eslint from '@eslint/js';
|
import eslint from '@eslint/js';
|
||||||
import prettierConfig from 'eslint-config-prettier';
|
import prettierConfig from 'eslint-config-prettier';
|
||||||
|
import { defineConfig } from 'eslint/config';
|
||||||
import tseslint from 'typescript-eslint';
|
import tseslint from 'typescript-eslint';
|
||||||
|
|
||||||
export default tseslint.config(
|
export default defineConfig(
|
||||||
eslint.configs.recommended,
|
eslint.configs.recommended,
|
||||||
...tseslint.configs.recommendedTypeChecked,
|
...tseslint.configs.recommendedTypeChecked,
|
||||||
prettierConfig,
|
prettierConfig,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "EMS-ESP",
|
"name": "EMS-ESP",
|
||||||
"version": "3.8.0",
|
"version": "3.8.2",
|
||||||
"description": "EMS-ESP WebUI",
|
"description": "EMS-ESP WebUI",
|
||||||
"homepage": "https://emsesp.org",
|
"homepage": "https://emsesp.org",
|
||||||
"author": "proddy, emsesp.org",
|
"author": "proddy, emsesp.org",
|
||||||
@@ -12,12 +12,12 @@
|
|||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build-hosted": "typesafe-i18n && vite build --mode hosted",
|
"build-hosted": "typesafe-i18n --no-watch && vite build --mode hosted",
|
||||||
"mock-rest": "bun --watch ../mock-api/restServer.ts",
|
"mock-rest": "bun --watch ../mock-api/restServer.ts",
|
||||||
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"pnpm:mock-rest\" \"vite preview\"",
|
"preview-standalone": "typesafe-i18n --no-watch && vite build && concurrently -c \"auto\" \"pnpm:mock-rest\" \"vite preview\"",
|
||||||
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"pnpm:mock-rest\" \"vite dev\"",
|
"standalone": "concurrently -c \"auto\" \"typesafe-i18n\" \"pnpm:mock-rest\" \"vite dev\"",
|
||||||
"typesafe-i18n": "typesafe-i18n --no-watch",
|
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||||
"build_webUI": "typesafe-i18n --no-watch && vite build && node progmem-generator.js",
|
"build-webUI": "typesafe-i18n --no-watch && vite build && 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",
|
||||||
"standalone-devcontainer": "concurrently -c \"auto\" \"typesafe-i18n\" \"pnpm:mock-rest\" \"vite --host\""
|
"standalone-devcontainer": "concurrently -c \"auto\" \"typesafe-i18n\" \"pnpm:mock-rest\" \"vite --host\""
|
||||||
@@ -26,46 +26,45 @@
|
|||||||
"@alova/adapter-xhr": "2.3.1",
|
"@alova/adapter-xhr": "2.3.1",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/icons-material": "^7.3.6",
|
"@mui/icons-material": "^9.0.0",
|
||||||
"@mui/material": "^7.3.6",
|
"@mui/material": "^9.0.0",
|
||||||
"@preact/compat": "^18.3.1",
|
"@preact/compat": "^18.3.2",
|
||||||
"@table-library/react-table-library": "4.1.15",
|
"@table-library/react-table-library": "4.1.15",
|
||||||
"alova": "3.4.1",
|
"alova": "^3.5.1",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
"etag": "^1.8.1",
|
"etag": "^1.8.1",
|
||||||
"formidable": "^3.5.4",
|
"formidable": "^3.5.4",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"magic-string": "^0.30.21",
|
"magic-string": "^0.30.21",
|
||||||
"mime-types": "^3.0.2",
|
"mime-types": "^3.0.2",
|
||||||
"preact": "^10.28.1",
|
"preact": "^10.29.1",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.5",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.5",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.6.0",
|
||||||
"react-router": "^7.11.0",
|
"react-router": "^7.14.2",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.1.0",
|
||||||
"typesafe-i18n": "^5.26.2",
|
"typesafe-i18n": "^5.27.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^6.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.28.5",
|
"@babel/core": "^7.29.0",
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^10.0.1",
|
||||||
"@preact/compat": "^18.3.1",
|
"@preact/compat": "^18.3.2",
|
||||||
"@preact/preset-vite": "^2.10.2",
|
"@preact/preset-vite": "^2.10.5",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^6.0.0",
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.6.0",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"axe-core": "^4.11.0",
|
"axe-core": "^4.11.3",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^10.2.1",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.8.3",
|
||||||
"rollup-plugin-visualizer": "^6.0.5",
|
"rollup-plugin-visualizer": "^7.0.1",
|
||||||
"terser": "^5.44.1",
|
"terser": "^5.46.1",
|
||||||
"typescript-eslint": "^8.51.0",
|
"typescript-eslint": "^8.59.0",
|
||||||
"vite": "^7.3.0",
|
"vite": "^8.0.9",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1"
|
||||||
"vite-tsconfig-paths": "^6.0.3"
|
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|
"packageManager": "pnpm@10.33.1+sha512.05ba3c1d5d1c18f68df06470d74055e62d41fc110a0c660db1b2dfb2785327f04cf0f68345d4609bc52089e7fa0343c31593b2f9594e2c5d5da426230acc9820"
|
||||||
}
|
}
|
||||||
|
|||||||
6584
interface/pnpm-lock.yaml
generated
Normal file
6584
interface/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,20 +24,26 @@ let bundleStats = {
|
|||||||
other: { count: 0, uncompressed: 0, compressed: 0 }
|
other: { count: 0, uncompressed: 0, compressed: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateWWWClass =
|
// AsyncWebHandler that performs the lookup.
|
||||||
() => `typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
|
const generateWWWClass = () => `// Bundle Statistics:
|
||||||
// Bundle Statistics:
|
|
||||||
// - Total compressed size: ${(totalSize / 1000).toFixed(1)} KB
|
// - 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
|
// - 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)}%
|
// - 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()}
|
// - Generated on: ${new Date().toISOString()}
|
||||||
|
|
||||||
class WWWData {
|
struct WWWAsset {
|
||||||
${INDENT}public:
|
${INDENT}const char * uri;
|
||||||
${INDENT.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
${INDENT}const char * contentType;
|
||||||
${fileInfo.map((f) => `${INDENT.repeat(3)}handler("${f.uri}", "${f.mimeType}", ${f.variable}, ${f.size}, ${f.hash});`).join('\n')}
|
${INDENT}const uint8_t * content;
|
||||||
${INDENT.repeat(2)}}
|
${INDENT}size_t len;
|
||||||
|
${INDENT}const char * etag; // already includes enclosing double quotes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const WWWAsset WWW_ASSETS[] = {
|
||||||
|
${fileInfo.map((f) => `${INDENT}{"${f.uri}", "${f.mimeType}", ${f.variable}, ${f.size}, "\\"${f.rawHash}\\""},`).join('\n')}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr size_t WWW_ASSETS_COUNT = sizeof(WWW_ASSETS) / sizeof(WWW_ASSETS[0]);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const getFilesSync = (dir, files = []) => {
|
const getFilesSync = (dir, files = []) => {
|
||||||
@@ -72,6 +78,7 @@ const writeFile = (relativeFilePath, buffer) => {
|
|||||||
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
|
||||||
// const hash = crypto.createHash('sha256').update(zipBuffer).digest('hex');
|
// const hash = crypto.createHash('sha256').update(zipBuffer).digest('hex');
|
||||||
const hash = etag(zipBuffer); // use smaller md5 instead of sha256
|
const hash = etag(zipBuffer); // use smaller md5 instead of sha256
|
||||||
|
const rawHash = hash.replace(/^"|"$/g, '');
|
||||||
|
|
||||||
zipBuffer.forEach((b) => {
|
zipBuffer.forEach((b) => {
|
||||||
if (!(size % bytesPerLine)) {
|
if (!(size % bytesPerLine)) {
|
||||||
@@ -94,7 +101,8 @@ const writeFile = (relativeFilePath, buffer) => {
|
|||||||
mimeType,
|
mimeType,
|
||||||
variable,
|
variable,
|
||||||
size,
|
size,
|
||||||
hash
|
hash,
|
||||||
|
rawHash
|
||||||
});
|
});
|
||||||
|
|
||||||
totalSize += size;
|
totalSize += size;
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
import { type FC, Suspense, lazy, memo, useContext, useEffect, useRef } from 'react';
|
import { type FC, memo, useContext, useEffect, useRef } from 'react';
|
||||||
import { Navigate, Route, Routes } from 'react-router';
|
import { Navigate, Route, Routes } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import {
|
import AuthenticatedRouting from 'AuthenticatedRouting';
|
||||||
LoadingSpinner,
|
import SignIn from 'SignIn';
|
||||||
RequireAuthenticated,
|
import { RequireAuthenticated, RequireUnauthenticated } from 'components';
|
||||||
RequireUnauthenticated
|
|
||||||
} from 'components';
|
|
||||||
import { Authentication, AuthenticationContext } from 'contexts/authentication';
|
import { Authentication, AuthenticationContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
// Lazy load route components for better code splitting
|
|
||||||
const SignIn = lazy(() => import('SignIn'));
|
|
||||||
const AuthenticatedRouting = lazy(() => import('AuthenticatedRouting'));
|
|
||||||
|
|
||||||
interface SecurityRedirectProps {
|
interface SecurityRedirectProps {
|
||||||
readonly message: string;
|
readonly message: string;
|
||||||
readonly signOut?: boolean;
|
readonly signOut?: boolean;
|
||||||
@@ -45,7 +39,6 @@ const AppRouting: FC = memo(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Authentication>
|
<Authentication>
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path="/unauthorized"
|
path="/unauthorized"
|
||||||
@@ -72,7 +65,6 @@ const AppRouting: FC = memo(() => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
|
||||||
</Authentication>
|
</Authentication>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,44 +1,39 @@
|
|||||||
import { Suspense, lazy, memo, useContext } from 'react';
|
import { memo, useContext } from 'react';
|
||||||
import { Navigate, Route, Routes } from 'react-router';
|
import { Navigate, Route, Routes } from 'react-router';
|
||||||
|
|
||||||
import { Layout, LoadingSpinner } from 'components';
|
import CustomEntities from 'app/main/CustomEntities';
|
||||||
|
import Customizations from 'app/main/Customizations';
|
||||||
|
import Dashboard from 'app/main/Dashboard';
|
||||||
|
import Devices from 'app/main/Devices';
|
||||||
|
import Help from 'app/main/Help';
|
||||||
|
import Modules from 'app/main/Modules';
|
||||||
|
import Scheduler from 'app/main/Scheduler';
|
||||||
|
import Sensors from 'app/main/Sensors';
|
||||||
|
import UserProfile from 'app/main/UserProfile';
|
||||||
|
import APSettings from 'app/settings/APSettings';
|
||||||
|
import ApplicationSettings from 'app/settings/ApplicationSettings';
|
||||||
|
import DownloadUpload from 'app/settings/DownloadUpload';
|
||||||
|
import MqttSettings from 'app/settings/MqttSettings';
|
||||||
|
import NTPSettings from 'app/settings/NTPSettings';
|
||||||
|
import Settings from 'app/settings/Settings';
|
||||||
|
import Network from 'app/settings/network/Network';
|
||||||
|
import Security from 'app/settings/security/Security';
|
||||||
|
import APStatus from 'app/status/APStatus';
|
||||||
|
import Activity from 'app/status/Activity';
|
||||||
|
import HardwareStatus from 'app/status/HardwareStatus';
|
||||||
|
import MqttStatus from 'app/status/MqttStatus';
|
||||||
|
import NTPStatus from 'app/status/NTPStatus';
|
||||||
|
import NetworkStatus from 'app/status/NetworkStatus';
|
||||||
|
import Status from 'app/status/Status';
|
||||||
|
import SystemLog from 'app/status/SystemLog';
|
||||||
|
import Version from 'app/status/Version';
|
||||||
|
import { Layout } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
|
||||||
// Lazy load all route components for better code splitting
|
|
||||||
const Dashboard = lazy(() => import('app/main/Dashboard'));
|
|
||||||
const Devices = lazy(() => import('app/main/Devices'));
|
|
||||||
const Sensors = lazy(() => import('app/main/Sensors'));
|
|
||||||
const Help = lazy(() => import('app/main/Help'));
|
|
||||||
const Customizations = lazy(() => import('app/main/Customizations'));
|
|
||||||
const Scheduler = lazy(() => import('app/main/Scheduler'));
|
|
||||||
const CustomEntities = lazy(() => import('app/main/CustomEntities'));
|
|
||||||
const Modules = lazy(() => import('app/main/Modules'));
|
|
||||||
const UserProfile = lazy(() => import('app/main/UserProfile'));
|
|
||||||
|
|
||||||
const Status = lazy(() => import('app/status/Status'));
|
|
||||||
const HardwareStatus = lazy(() => import('app/status/HardwareStatus'));
|
|
||||||
const Activity = lazy(() => import('app/status/Activity'));
|
|
||||||
const SystemLog = lazy(() => import('app/status/SystemLog'));
|
|
||||||
const MqttStatus = lazy(() => import('app/status/MqttStatus'));
|
|
||||||
const NTPStatus = lazy(() => import('app/status/NTPStatus'));
|
|
||||||
const APStatus = lazy(() => import('app/status/APStatus'));
|
|
||||||
const NetworkStatus = lazy(() => import('app/status/NetworkStatus'));
|
|
||||||
const Version = lazy(() => import('app/status/Version'));
|
|
||||||
|
|
||||||
const Settings = lazy(() => import('app/settings/Settings'));
|
|
||||||
const ApplicationSettings = lazy(() => import('app/settings/ApplicationSettings'));
|
|
||||||
const MqttSettings = lazy(() => import('app/settings/MqttSettings'));
|
|
||||||
const NTPSettings = lazy(() => import('app/settings/NTPSettings'));
|
|
||||||
const APSettings = lazy(() => import('app/settings/APSettings'));
|
|
||||||
const DownloadUpload = lazy(() => import('app/settings/DownloadUpload'));
|
|
||||||
const Network = lazy(() => import('app/settings/network/Network'));
|
|
||||||
const Security = lazy(() => import('app/settings/security/Security'));
|
|
||||||
|
|
||||||
const AuthenticatedRouting = memo(() => {
|
const AuthenticatedRouting = memo(() => {
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/dashboard/*" element={<Dashboard />} />
|
<Route path="/dashboard/*" element={<Dashboard />} />
|
||||||
<Route path="/devices/*" element={<Devices />} />
|
<Route path="/devices/*" element={<Devices />} />
|
||||||
@@ -59,10 +54,7 @@ const AuthenticatedRouting = memo(() => {
|
|||||||
{me.admin && (
|
{me.admin && (
|
||||||
<>
|
<>
|
||||||
<Route path="/settings" element={<Settings />} />
|
<Route path="/settings" element={<Settings />} />
|
||||||
<Route
|
<Route path="/settings/application" element={<ApplicationSettings />} />
|
||||||
path="/settings/application"
|
|
||||||
element={<ApplicationSettings />}
|
|
||||||
/>
|
|
||||||
<Route path="/settings/mqtt" element={<MqttSettings />} />
|
<Route path="/settings/mqtt" element={<MqttSettings />} />
|
||||||
<Route path="/settings/ntp" element={<NTPSettings />} />
|
<Route path="/settings/ntp" element={<NTPSettings />} />
|
||||||
<Route path="/settings/ap" element={<APSettings />} />
|
<Route path="/settings/ap" element={<APSettings />} />
|
||||||
@@ -80,7 +72,6 @@ const AuthenticatedRouting = memo(() => {
|
|||||||
|
|
||||||
<Route path="/*" element={<Navigate to="/" />} />
|
<Route path="/*" element={<Navigate to="/" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
|
|||||||
|
|
||||||
import ForwardIcon from '@mui/icons-material/Forward';
|
import ForwardIcon from '@mui/icons-material/Forward';
|
||||||
import { Box, Button, Paper, Typography } from '@mui/material';
|
import { Box, Button, Paper, Typography } from '@mui/material';
|
||||||
|
import type { Theme } from '@mui/material/styles';
|
||||||
|
|
||||||
import * as AuthenticationApi from 'components/routing/authentication';
|
import * as AuthenticationApi from 'components/routing/authentication';
|
||||||
import { useRequest } from 'alova/client';
|
import { useRequest } from 'alova/client';
|
||||||
@@ -17,7 +18,7 @@ import { PROJECT_NAME } from 'env';
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { SignInRequest } from 'types';
|
import type { SignInRequest } from 'types';
|
||||||
import { onEnterCallback, updateValue } from 'utils';
|
import { onEnterCallback, updateValue } from 'utils';
|
||||||
import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
|
import { SIGN_IN_REQUEST_VALIDATOR, ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
const SignIn = memo(() => {
|
const SignIn = memo(() => {
|
||||||
const authenticationContext = useContext(AuthenticationContext);
|
const authenticationContext = useContext(AuthenticationContext);
|
||||||
@@ -36,7 +37,7 @@ const SignIn = memo(() => {
|
|||||||
{
|
{
|
||||||
immediate: false
|
immediate: false
|
||||||
}
|
}
|
||||||
).onSuccess((response) => {
|
).onSuccess((response: { data: { access_token: string } }) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
authenticationContext.signIn(response.data.access_token);
|
authenticationContext.signIn(response.data.access_token);
|
||||||
}
|
}
|
||||||
@@ -73,12 +74,11 @@ const SignIn = memo(() => {
|
|||||||
await validate(SIGN_IN_REQUEST_VALIDATOR, signInRequest);
|
await validate(SIGN_IN_REQUEST_VALIDATOR, signInRequest);
|
||||||
await signIn();
|
await signIn();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
setProcessing(false);
|
setProcessing(false);
|
||||||
}
|
}
|
||||||
}, [signInRequest, signIn, LL]);
|
}, [signInRequest, signIn, LL]);
|
||||||
|
|
||||||
// Memoize callback to prevent recreation on every render
|
|
||||||
const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]);
|
const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]);
|
||||||
|
|
||||||
// get rid of scrollbar
|
// get rid of scrollbar
|
||||||
@@ -92,13 +92,15 @@ const SignIn = memo(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
sx={(theme: Theme) => ({
|
||||||
height="100vh"
|
display: 'flex',
|
||||||
margin="auto"
|
height: '100vh',
|
||||||
padding={2}
|
margin: 'auto',
|
||||||
justifyContent="center"
|
padding: 2,
|
||||||
flexDirection="column"
|
justifyContent: 'center',
|
||||||
maxWidth={(theme) => theme.breakpoints.values.sm}
|
flexDirection: 'column',
|
||||||
|
maxWidth: theme.breakpoints.values.sm
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Paper
|
<Paper
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
@@ -111,16 +113,18 @@ const SignIn = memo(() => {
|
|||||||
width: '100%'
|
width: '100%'
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Typography mb={1} variant="h4">
|
<Typography sx={{ mb: 1 }} variant="h4">
|
||||||
{PROJECT_NAME}
|
{PROJECT_NAME}
|
||||||
</Typography>
|
</Typography>
|
||||||
<LanguageSelector />
|
<LanguageSelector />
|
||||||
<Box
|
<Box
|
||||||
mt={1}
|
sx={{
|
||||||
display="flex"
|
mt: 1,
|
||||||
flexDirection="column"
|
display: 'flex',
|
||||||
gap={1}
|
flexDirection: 'column',
|
||||||
alignItems="center"
|
gap: 1,
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors || {}}
|
fieldErrors={fieldErrors || {}}
|
||||||
|
|||||||
@@ -310,13 +310,15 @@ const CustomEntities = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Cell>
|
</Cell>
|
||||||
|
<Cell>{ei.ram > 0 ? '' : showHex(ei.device_id as number, 2)}</Cell>
|
||||||
|
<Cell>{ei.ram > 0 ? '' : showHex(ei.type_id as number, 3)}</Cell>
|
||||||
|
<Cell>{ei.ram > 0 ? '' : ei.offset}</Cell>
|
||||||
<Cell>
|
<Cell>
|
||||||
{ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}
|
{ei.ram === 1
|
||||||
</Cell>
|
? 'RAM'
|
||||||
<Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
|
: ei.ram === 2
|
||||||
<Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
|
? 'NVS'
|
||||||
<Cell>
|
: DeviceValueTypeNames[ei.value_type]}
|
||||||
{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}
|
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -341,9 +343,9 @@ const CustomEntities = () => {
|
|||||||
return (
|
return (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||||
<Typography variant="body1">{LL.ENTITIES_HELP_1()}.</Typography>
|
{LL.ENTITIES_HELP_1()}.
|
||||||
</Box>
|
</Typography>
|
||||||
|
|
||||||
{renderEntity()}
|
{renderEntity()}
|
||||||
|
|
||||||
@@ -359,8 +361,8 @@ const CustomEntities = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box mt={2} display="flex" flexWrap="wrap">
|
<Box sx={{ mt: 2, display: 'flex', flexWrap: 'wrap' }}>
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
{numChanges > 0 && (
|
{numChanges > 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
@@ -382,7 +384,7 @@ const CustomEntities = () => {
|
|||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<AddIcon />}
|
startIcon={<AddIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import DoneIcon from '@mui/icons-material/Done';
|
|||||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
||||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@@ -28,7 +28,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
|||||||
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValue } from 'utils';
|
import { numberValue, updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import { DeviceValueType, DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
import { DeviceValueType, DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
||||||
import type { EntityItem } from './types';
|
import type { EntityItem } from './types';
|
||||||
@@ -136,7 +136,7 @@ const CustomEntitiesDialog = ({
|
|||||||
}
|
}
|
||||||
onSave(processedItem);
|
onSave(processedItem);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [validator, editItem, onSave]);
|
}, [validator, editItem, onSave]);
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ const CustomEntitiesDialog = ({
|
|||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid mt={3}>
|
<Grid sx={{ mt: 3 }}>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -205,16 +205,17 @@ const CustomEntitiesDialog = ({
|
|||||||
>
|
>
|
||||||
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
|
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
|
||||||
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
|
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
|
||||||
|
<MenuItem value={2}>NVS-{LL.VALUE(1)}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
{editItem.ram === 1 && (
|
{editItem.ram > 0 && (
|
||||||
<>
|
<>
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="value"
|
name="value"
|
||||||
label={LL.DEFAULT(0) + ' ' + LL.VALUE(0)}
|
label={LL.DEFAULT(0) + ' ' + LL.VALUE(0)}
|
||||||
type="string"
|
type="string"
|
||||||
value={editItem.value as string}
|
value={editItem.value}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -237,7 +238,7 @@ const CustomEntitiesDialog = ({
|
|||||||
)}
|
)}
|
||||||
{editItem.ram === 0 && (
|
{editItem.ram === 0 && (
|
||||||
<>
|
<>
|
||||||
<Grid mt={3}>
|
<Grid sx={{ mt: 3 }}>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -259,7 +260,7 @@ const CustomEntitiesDialog = ({
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
sx={{ width: '11ch' }}
|
sx={{ width: '11ch' }}
|
||||||
type="string"
|
type="string"
|
||||||
value={editItem.device_id as string}
|
value={editItem.device_id}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
input: {
|
input: {
|
||||||
@@ -279,7 +280,7 @@ const CustomEntitiesDialog = ({
|
|||||||
margin="normal"
|
margin="normal"
|
||||||
sx={{ width: '11ch' }}
|
sx={{ width: '11ch' }}
|
||||||
type="string"
|
type="string"
|
||||||
value={editItem.type_id as string}
|
value={editItem.type_id}
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
input: {
|
input: {
|
||||||
@@ -380,7 +381,7 @@ const CustomEntitiesDialog = ({
|
|||||||
fieldErrors={fieldErrors || {}}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="factor"
|
name="factor"
|
||||||
label={LL.BITMASK()}
|
label={LL.BITMASK()}
|
||||||
value={editItem.factor as string}
|
value={editItem.factor}
|
||||||
sx={{ width: '11ch' }}
|
sx={{ width: '11ch' }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
@@ -403,7 +404,7 @@ const CustomEntitiesDialog = ({
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{!creating && (
|
{!creating && (
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<RemoveIcon />}
|
startIcon={<RemoveIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -111,13 +111,14 @@ const Customizations = () => {
|
|||||||
const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] =
|
const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] =
|
||||||
useState<string>(''); // needed for API URL
|
useState<string>(''); // needed for API URL
|
||||||
const [selectedDeviceName, setSelectedDeviceName] = useState<string>('');
|
const [selectedDeviceName, setSelectedDeviceName] = useState<string>('');
|
||||||
|
const [selectedDeviceBrand, setSelectedDeviceBrand] = useState<string>('');
|
||||||
|
|
||||||
const { send: sendResetCustomizations } = useRequest(resetCustomizations(), {
|
const { send: sendResetCustomizations } = useRequest(resetCustomizations(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: sendDeviceName } = useRequest(
|
const { send: sendDeviceName } = useRequest(
|
||||||
(data: { id: number; name: string }) => writeDeviceName(data),
|
(data: { id: number; name: string; brand: string }) => writeDeviceName(data),
|
||||||
{
|
{
|
||||||
immediate: false
|
immediate: false
|
||||||
}
|
}
|
||||||
@@ -267,6 +268,7 @@ const Customizations = () => {
|
|||||||
if (device) {
|
if (device) {
|
||||||
setSelectedDeviceTypeNameURL(device.url || '');
|
setSelectedDeviceTypeNameURL(device.url || '');
|
||||||
setSelectedDeviceName(device.n);
|
setSelectedDeviceName(device.n);
|
||||||
|
setSelectedDeviceBrand(device.b);
|
||||||
}
|
}
|
||||||
setNumChanges(0);
|
setNumChanges(0);
|
||||||
setRestartNeeded(false);
|
setRestartNeeded(false);
|
||||||
@@ -442,7 +444,11 @@ const Customizations = () => {
|
|||||||
}, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]);
|
}, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]);
|
||||||
|
|
||||||
const renameDevice = useCallback(async () => {
|
const renameDevice = useCallback(async () => {
|
||||||
await sendDeviceName({ id: selectedDevice, name: selectedDeviceName })
|
await sendDeviceName({
|
||||||
|
id: selectedDevice,
|
||||||
|
name: selectedDeviceName,
|
||||||
|
brand: selectedDeviceBrand
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.UPDATED_OF(LL.NAME(1)));
|
toast.success(LL.UPDATED_OF(LL.NAME(1)));
|
||||||
})
|
})
|
||||||
@@ -453,24 +459,42 @@ const Customizations = () => {
|
|||||||
setRename(false);
|
setRename(false);
|
||||||
await fetchCoreData();
|
await fetchCoreData();
|
||||||
});
|
});
|
||||||
}, [selectedDevice, selectedDeviceName, sendDeviceName, LL, fetchCoreData]);
|
}, [
|
||||||
|
selectedDevice,
|
||||||
|
selectedDeviceName,
|
||||||
|
selectedDeviceBrand,
|
||||||
|
sendDeviceName,
|
||||||
|
LL,
|
||||||
|
fetchCoreData
|
||||||
|
]);
|
||||||
|
|
||||||
const renderDeviceList = () => (
|
const renderDeviceList = () => (
|
||||||
<>
|
<>
|
||||||
<Box mb={1} color="warning.main">
|
<Typography sx={{ mb: 1 }} color="warning" variant="body1">
|
||||||
<Typography variant="body1">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
{LL.CUSTOMIZATIONS_HELP_1()}.
|
||||||
</Box>
|
</Typography>
|
||||||
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 2 }}>
|
||||||
{rename ? (
|
{rename ? (
|
||||||
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
name="device"
|
name="device"
|
||||||
label={LL.EMS_DEVICE()}
|
label={LL.EMS_DEVICE()}
|
||||||
fullWidth
|
style={{ minWidth: '48%' }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={selectedDeviceName}
|
value={selectedDeviceName}
|
||||||
onChange={(e) => setSelectedDeviceName(e.target.value)}
|
onChange={(e) => setSelectedDeviceName(e.target.value)}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
|
<TextField
|
||||||
|
name="brand"
|
||||||
|
label={LL.BRAND()}
|
||||||
|
style={{ minWidth: '48%' }}
|
||||||
|
variant="outlined"
|
||||||
|
value={selectedDeviceBrand}
|
||||||
|
onChange={(e) => setSelectedDeviceBrand(e.target.value)}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<TextField
|
<TextField
|
||||||
name="device"
|
name="device"
|
||||||
@@ -546,27 +570,22 @@ const Customizations = () => {
|
|||||||
const renderDeviceData = () => {
|
const renderDeviceData = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box color="warning.main">
|
<Typography sx={{ mt: 1, mb: 1 }} color="warning" variant="body2">
|
||||||
<Typography variant="body2" mt={1} mb={1}>
|
|
||||||
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
||||||
|
|
||||||
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
||||||
|
|
||||||
<OptionIcon type="api_mqtt_exclude" isSet={true} />=
|
<OptionIcon type="api_mqtt_exclude" isSet={true} />=
|
||||||
{LL.CUSTOMIZATIONS_HELP_4()}
|
{LL.CUSTOMIZATIONS_HELP_4()}
|
||||||
<OptionIcon type="web_exclude" isSet={true} />=
|
<OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()}
|
||||||
{LL.CUSTOMIZATIONS_HELP_5()}
|
|
||||||
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
mb={1}
|
|
||||||
mt={0}
|
|
||||||
spacing={2}
|
spacing={2}
|
||||||
direction="row"
|
direction="row"
|
||||||
justifyContent="flex-start"
|
sx={{ mb: 1, mt: 0, justifyContent: 'flex-start', alignItems: 'center' }}
|
||||||
alignItems="center"
|
|
||||||
>
|
>
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -755,8 +774,8 @@ const Customizations = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</MessageBox>
|
</MessageBox>
|
||||||
) : (
|
) : (
|
||||||
<Box display="flex" flexWrap="wrap">
|
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
{numChanges !== 0 && (
|
{numChanges !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
@@ -788,10 +807,12 @@ const Customizations = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return restarting ? (
|
||||||
|
<SystemMonitor />
|
||||||
|
) : (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <SystemMonitor /> : renderContent()}
|
{renderContent()}
|
||||||
{selectedDeviceEntity && (
|
{selectedDeviceEntity && (
|
||||||
<SettingsCustomizationsDialog
|
<SettingsCustomizationsDialog
|
||||||
open={dialogOpen}
|
open={dialogOpen}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ interface LabelValueProps {
|
|||||||
|
|
||||||
const LabelValue = memo(({ label, value }: LabelValueProps) => (
|
const LabelValue = memo(({ label, value }: LabelValueProps) => (
|
||||||
<Grid container direction="row">
|
<Grid container direction="row">
|
||||||
<Typography variant="body2" color="warning.main">
|
<Typography variant="body2" color="warning">
|
||||||
{label}:
|
{label}:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2">{value}</Typography>
|
<Typography variant="body2">{value}</Typography>
|
||||||
@@ -131,7 +131,7 @@ const CustomizationsDialog = ({
|
|||||||
/>
|
/>
|
||||||
<LabelValue label={LL.WRITEABLE()} value={writeableIcon} />
|
<LabelValue label={LL.WRITEABLE()} value={writeableIcon} />
|
||||||
|
|
||||||
<Box mt={1} mb={2}>
|
<Box sx={{ mt: 1, mb: 2 }}>
|
||||||
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
|
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ const CustomizationsDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<Typography variant="body2" color="error" mt={2}>
|
<Typography sx={{ mt: 2 }} variant="body2" color="error">
|
||||||
Error: Check min and max values
|
Error: Check min and max values
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { toast } from 'react-toastify';
|
|||||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
|
import HelpOutlineIcon from '@mui/icons-material/HelpOutlined';
|
||||||
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
|
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
|
||||||
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
|
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
|
||||||
import {
|
import {
|
||||||
@@ -262,12 +262,8 @@ const Dashboard = memo(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!data.connected && (
|
|
||||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{data.connected && data.nodes.length > 0 && !hasFavEntities && (
|
{data.connected && data.nodes.length > 0 && !hasFavEntities && (
|
||||||
<MessageBox mb={2} level="warning">
|
<MessageBox sx={{ mb: 2 }} level="warning">
|
||||||
<Typography>
|
<Typography>
|
||||||
{LL.NO_DATA_1()}
|
{LL.NO_DATA_1()}
|
||||||
<Link to="/customizations" style={{ color: 'white' }}>
|
<Link to="/customizations" style={{ color: 'white' }}>
|
||||||
@@ -284,10 +280,12 @@ const Dashboard = memo(() => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
sx={{
|
||||||
justifyContent="flex-end"
|
display: 'flex',
|
||||||
flexWrap="nowrap"
|
justifyContent: 'flex-end',
|
||||||
whiteSpace="nowrap"
|
flexWrap: 'nowrap',
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
size="small"
|
size="small"
|
||||||
@@ -310,7 +308,7 @@ const Dashboard = memo(() => {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{data.nodes.length > 0 ? (
|
{data.nodes.length > 0 ? (
|
||||||
<Box mt={1} justifyContent="center" flexDirection="column">
|
<Box sx={{ mt: 1, justifyContent: 'center', flexDirection: 'column' }}>
|
||||||
<IconContext.Provider
|
<IconContext.Provider
|
||||||
value={{
|
value={{
|
||||||
color: 'lightblue',
|
color: 'lightblue',
|
||||||
@@ -377,13 +375,8 @@ const Dashboard = memo(() => {
|
|||||||
</IconContext.Provider>
|
</IconContext.Provider>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box sx={{ display: 'flex' }}>
|
||||||
display="flex"
|
<Typography sx={{ mt: 1 }} color="warning" variant="body1">
|
||||||
// justifyContent="flex-end"
|
|
||||||
// flexWrap="nowrap"
|
|
||||||
// whiteSpace="nowrap"
|
|
||||||
>
|
|
||||||
<Typography mt={1} color="warning.main" variant="body1">
|
|
||||||
no data
|
no data
|
||||||
</Typography>
|
</Typography>
|
||||||
<Tooltip title={LL.DASHBOARD_1()}>
|
<Tooltip title={LL.DASHBOARD_1()}>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import type { IconType } from 'react-icons';
|
||||||
import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai';
|
import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai';
|
||||||
import { CgSmartHomeBoiler } from 'react-icons/cg';
|
import { CgSmartHomeBoiler } from 'react-icons/cg';
|
||||||
import { FaSolarPanel } from 'react-icons/fa';
|
import { FaSolarPanel } from 'react-icons/fa';
|
||||||
@@ -15,14 +16,9 @@ import { PiFan, PiGauge } from 'react-icons/pi';
|
|||||||
import { TiFlowSwitch, TiThermometer } from 'react-icons/ti';
|
import { TiFlowSwitch, TiThermometer } from 'react-icons/ti';
|
||||||
import { VscVmConnect } from 'react-icons/vsc';
|
import { VscVmConnect } from 'react-icons/vsc';
|
||||||
|
|
||||||
import type { SvgIconProps } from '@mui/material';
|
|
||||||
|
|
||||||
import { DeviceType } from './types';
|
import { DeviceType } from './types';
|
||||||
|
|
||||||
const deviceIconLookup: Record<
|
const deviceIconLookup: Record<DeviceType, IconType | null> = {
|
||||||
DeviceType,
|
|
||||||
React.ComponentType<SvgIconProps> | null
|
|
||||||
> = {
|
|
||||||
[DeviceType.TEMPERATURESENSOR]: TiThermometer,
|
[DeviceType.TEMPERATURESENSOR]: TiThermometer,
|
||||||
[DeviceType.ANALOGSENSOR]: PiGauge,
|
[DeviceType.ANALOGSENSOR]: PiGauge,
|
||||||
[DeviceType.BOILER]: CgSmartHomeBoiler,
|
[DeviceType.BOILER]: CgSmartHomeBoiler,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { IconContext } from 'react-icons';
|
import { IconContext } from 'react-icons';
|
||||||
import { useNavigate } from 'react-router';
|
import { Link, useNavigate } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||||
@@ -534,9 +534,19 @@ const Devices = memo(() => {
|
|||||||
const renderCoreData = () => (
|
const renderCoreData = () => (
|
||||||
<>
|
<>
|
||||||
{!coreData.connected ? (
|
{!coreData.connected ? (
|
||||||
<MessageBox level="error" message={LL.EMS_BUS_WARNING()} />
|
<MessageBox level="error" message={LL.EMS_BUS_WARNING() + '.'}>
|
||||||
|
(
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
to="https://docs.emsesp.org/Troubleshooting#ems-bus-is-not-connecting"
|
||||||
|
style={{ color: 'white' }}
|
||||||
|
>
|
||||||
|
{LL.ONLINE_HELP()}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
</MessageBox>
|
||||||
) : (
|
) : (
|
||||||
<Box justifyContent="center" flexDirection="column">
|
<Box sx={{ justifyContent: 'center', flexDirection: 'column' }}>
|
||||||
<IconContext.Provider
|
<IconContext.Provider
|
||||||
value={{
|
value={{
|
||||||
color: 'lightblue',
|
color: 'lightblue',
|
||||||
@@ -660,12 +670,12 @@ const Devices = memo(() => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ p: 1 }}>
|
<Box sx={{ p: 1 }}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container sx={{ justifyContent: 'space-between' }}>
|
||||||
<Typography noWrap variant="subtitle1" color="warning.main">
|
<Typography noWrap variant="subtitle1" color="warning">
|
||||||
{deviceInfo.n} (
|
{deviceInfo.n} (
|
||||||
{deviceInfo.tn})
|
{deviceInfo.tn})
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid justifyContent="flex-end">
|
<Grid sx={{ justifyContent: 'flex-end' }}>
|
||||||
<ButtonTooltip title={LL.CLOSE()}>
|
<ButtonTooltip title={LL.CLOSE()}>
|
||||||
<IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}>
|
<IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}>
|
||||||
<HighlightOffIcon color="primary" sx={{ fontSize: 18 }} />
|
<HighlightOffIcon color="primary" sx={{ fontSize: 18 }} />
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
|||||||
import { ValidatedTextField } from 'components';
|
import { ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValue } from 'utils';
|
import { numberValue, updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import { DeviceValueUOM, DeviceValueUOM_s } from './types';
|
import { DeviceValueUOM, DeviceValueUOM_s } from './types';
|
||||||
import type { DeviceValue } from './types';
|
import type { DeviceValue } from './types';
|
||||||
@@ -67,7 +67,7 @@ const DevicesDialog = ({
|
|||||||
await validate(validator, editItem);
|
await validate(validator, editItem);
|
||||||
onSave(editItem);
|
onSave(editItem);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [validator, editItem, onSave]);
|
}, [validator, editItem, onSave]);
|
||||||
|
|
||||||
@@ -128,9 +128,9 @@ const DevicesDialog = ({
|
|||||||
<Dialog sx={dialogStyle} open={open} onClose={onClose}>
|
<Dialog sx={dialogStyle} open={open} onClose={onClose}>
|
||||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Box color="warning.main" mb={2}>
|
<Typography sx={{ mb: 2 }} color="warning" variant="body2">
|
||||||
<Typography variant="body2">{editItem.id.slice(2)}</Typography>
|
{editItem.id.slice(2)}
|
||||||
</Box>
|
</Typography>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid size={12}>
|
<Grid size={12}>
|
||||||
{editItem.l ? (
|
{editItem.l ? (
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
|
Grid,
|
||||||
Link,
|
Link,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
@@ -42,7 +43,7 @@ interface CustomSupport {
|
|||||||
html: string | null;
|
html: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_IMAGE_URL = 'https://emsesp.org/_media/images/installer.jpeg';
|
const DEFAULT_IMAGE_URL = 'https://emsesp.org/media/images/installer.jpeg';
|
||||||
|
|
||||||
const SUPPORT_BOX_STYLES: SxProps<Theme> = {
|
const SUPPORT_BOX_STYLES: SxProps<Theme> = {
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
@@ -71,7 +72,6 @@ const HelpComponent = () => {
|
|||||||
});
|
});
|
||||||
const [imgError, setImgError] = useState<boolean>(false);
|
const [imgError, setImgError] = useState<boolean>(false);
|
||||||
|
|
||||||
// Memoize the request method to prevent re-creation on every render
|
|
||||||
const getCustomSupportMethod = useMemo(
|
const getCustomSupportMethod = useMemo(
|
||||||
() => callAction({ action: 'getCustomSupport' }),
|
() => callAction({ action: 'getCustomSupport' }),
|
||||||
[]
|
[]
|
||||||
@@ -120,7 +120,7 @@ const HelpComponent = () => {
|
|||||||
label: () => LL.HELP_INFORMATION_1()
|
label: () => LL.HELP_INFORMATION_1()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: 'https://discord.gg/3J3GgnzpyT',
|
href: 'https://discord.gg/GP9DPSgeJq',
|
||||||
icon: <CommentIcon />,
|
icon: <CommentIcon />,
|
||||||
label: () => LL.HELP_INFORMATION_2()
|
label: () => LL.HELP_INFORMATION_2()
|
||||||
},
|
},
|
||||||
@@ -146,11 +146,9 @@ const HelpComponent = () => {
|
|||||||
<SectionContent>
|
<SectionContent>
|
||||||
{customSupport.html && (
|
{customSupport.html && (
|
||||||
<Stack
|
<Stack
|
||||||
padding={1}
|
|
||||||
mb={2}
|
|
||||||
direction="row"
|
direction="row"
|
||||||
divider={<Divider orientation="vertical" flexItem />}
|
divider={<Divider orientation="vertical" flexItem />}
|
||||||
sx={SUPPORT_BOX_STYLES}
|
sx={{ padding: 1, mb: 2, ...SUPPORT_BOX_STYLES }}
|
||||||
>
|
>
|
||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
<div dangerouslySetInnerHTML={{ __html: customSupport.html }} />
|
<div dangerouslySetInnerHTML={{ __html: customSupport.html }} />
|
||||||
@@ -185,9 +183,9 @@ const HelpComponent = () => {
|
|||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box p={2} color="warning.main">
|
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}>
|
||||||
<Typography mb={1} variant="body1">
|
<Typography sx={{ mb: 1 }} color="warning" variant="body1">
|
||||||
{LL.HELP_INFORMATION_4()}.
|
{LL.HELP_INFORMATION_4()}:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<DownloadIcon />}
|
startIcon={<DownloadIcon />}
|
||||||
@@ -197,11 +195,11 @@ const HelpComponent = () => {
|
|||||||
>
|
>
|
||||||
{LL.SUPPORT_INFORMATION(0)}
|
{LL.SUPPORT_INFORMATION(0)}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Grid>
|
||||||
|
|
||||||
<Divider sx={{ mt: 4 }} />
|
<Divider sx={{ mt: 4 }} />
|
||||||
|
|
||||||
<Typography color="white" variant="subtitle1" align="center" mt={1}>
|
<Typography color="white" variant="subtitle1" align="center" sx={{ mt: 1 }}>
|
||||||
©
|
©
|
||||||
<Link
|
<Link
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -186,9 +186,9 @@ const Modules = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box mb={2} color="warning.main">
|
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||||
<Typography variant="body1">{LL.MODULES_DESCRIPTION()}.</Typography>
|
{LL.MODULES_DESCRIPTION()}.
|
||||||
</Box>
|
</Typography>
|
||||||
<Table
|
<Table
|
||||||
data={{ nodes: modules }}
|
data={{ nodes: modules }}
|
||||||
theme={modules_theme}
|
theme={modules_theme}
|
||||||
@@ -236,8 +236,8 @@ const Modules = () => {
|
|||||||
)}
|
)}
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
<Box mt={1} display="flex" flexWrap="wrap">
|
<Box sx={{ mt: 1, display: 'flex', flexWrap: 'wrap' }}>
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
{numChanges !== 0 && (
|
{numChanges !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const ModulesDialog = ({
|
|||||||
label="Enabled"
|
label="Enabled"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Box mt={2} mb={1}>
|
<Box sx={{ mt: 2, mb: 1 }}>
|
||||||
<TextField
|
<TextField
|
||||||
name="license"
|
name="license"
|
||||||
label="License Key"
|
label="License Key"
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { memo } from 'react';
|
|||||||
|
|
||||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
|
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
|
||||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutlined';
|
||||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||||
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import StarIcon from '@mui/icons-material/Star';
|
||||||
import StarOutlineIcon from '@mui/icons-material/StarOutline';
|
import StarOutlineIcon from '@mui/icons-material/StarOutlined';
|
||||||
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
|
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
|
||||||
import type { SvgIconProps } from '@mui/material';
|
import type { SvgIconProps } from '@mui/material';
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const MIN_ID = -100;
|
|||||||
const MAX_ID = 100;
|
const MAX_ID = 100;
|
||||||
const ICON_SIZE = 16;
|
const ICON_SIZE = 16;
|
||||||
const SCHEDULE_FLAG_THRESHOLD = 127;
|
const SCHEDULE_FLAG_THRESHOLD = 127;
|
||||||
|
const FLAG_ALL_DAYS = 127;
|
||||||
const REFERENCE_YEAR = 2017;
|
const REFERENCE_YEAR = 2017;
|
||||||
const REFERENCE_MONTH = '01';
|
const REFERENCE_MONTH = '01';
|
||||||
const LOG_2 = Math.log(2);
|
const LOG_2 = Math.log(2);
|
||||||
@@ -51,7 +52,7 @@ const WEEK_DAYS = [1, 2, 3, 4, 5, 6, 7] as const;
|
|||||||
const DEFAULT_SCHEDULE_ITEM: Omit<ScheduleItem, 'id' | 'o_id'> = {
|
const DEFAULT_SCHEDULE_ITEM: Omit<ScheduleItem, 'id' | 'o_id'> = {
|
||||||
active: false,
|
active: false,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
flags: ScheduleFlag.SCHEDULE_DAY,
|
flags: FLAG_ALL_DAYS,
|
||||||
time: '',
|
time: '',
|
||||||
cmd: '',
|
cmd: '',
|
||||||
value: '',
|
value: '',
|
||||||
@@ -357,9 +358,9 @@ const Scheduler = () => {
|
|||||||
return (
|
return (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||||
<Typography variant="body1">{LL.SCHEDULER_HELP_1()}.</Typography>
|
{LL.SCHEDULER_HELP_1()}.
|
||||||
</Box>
|
</Typography>
|
||||||
{renderSchedule()}
|
{renderSchedule()}
|
||||||
|
|
||||||
{selectedScheduleItem && (
|
{selectedScheduleItem && (
|
||||||
@@ -374,8 +375,8 @@ const Scheduler = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box display="flex" flexWrap="wrap">
|
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
{numChanges !== 0 && (
|
{numChanges !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
@@ -397,7 +398,7 @@ const Scheduler = () => {
|
|||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<AddIcon />}
|
startIcon={<AddIcon />}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import AddIcon from '@mui/icons-material/Add';
|
|||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@@ -26,14 +26,15 @@ import type { ValidateFieldsError } from 'async-validator';
|
|||||||
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { updateValue } from 'utils';
|
import { updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import { ScheduleFlag } from './types';
|
import { ScheduleFlag } from './types';
|
||||||
import type { ScheduleItem } from './types';
|
import type { ScheduleItem } from './types';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const FLAG_MASK_127 = 127;
|
const FLAG_MASK_127 = 127;
|
||||||
const SCHEDULE_TYPE_THRESHOLD = 128;
|
const SCHEDULE_TYPE_THRESHOLD = 127;
|
||||||
|
const FLAG_ALL_DAYS = 127;
|
||||||
const DEFAULT_TIME = '00:00';
|
const DEFAULT_TIME = '00:00';
|
||||||
const TYPOGRAPHY_FONT_SIZE = 10;
|
const TYPOGRAPHY_FONT_SIZE = 10;
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ const SchedulerDialog = ({
|
|||||||
// 130 is on condition
|
// 130 is on condition
|
||||||
// 132 is immediate
|
// 132 is immediate
|
||||||
setScheduleType(
|
setScheduleType(
|
||||||
selectedItem.flags < SCHEDULE_TYPE_THRESHOLD
|
selectedItem.flags <= SCHEDULE_TYPE_THRESHOLD
|
||||||
? ScheduleFlag.SCHEDULE_DAY
|
? ScheduleFlag.SCHEDULE_DAY
|
||||||
: selectedItem.flags
|
: selectedItem.flags
|
||||||
);
|
);
|
||||||
@@ -119,7 +120,7 @@ const SchedulerDialog = ({
|
|||||||
await validate(validator, itemToSave);
|
await validate(validator, itemToSave);
|
||||||
onSave(itemToSave);
|
onSave(itemToSave);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[validator, onSave]
|
[validator, onSave]
|
||||||
@@ -181,7 +182,7 @@ const SchedulerDialog = ({
|
|||||||
setScheduleType(flag);
|
setScheduleType(flag);
|
||||||
// wipe the time field when changing the schedule type
|
// wipe the time field when changing the schedule type
|
||||||
// set the flags based on type
|
// set the flags based on type
|
||||||
const newFlags = flag === ScheduleFlag.SCHEDULE_DAY ? 0 : flag;
|
const newFlags = flag === ScheduleFlag.SCHEDULE_DAY ? FLAG_ALL_DAYS : flag;
|
||||||
setEditItem((prev) => ({ ...prev, time: '', flags: newFlags }));
|
setEditItem((prev) => ({ ...prev, time: '', flags: newFlags }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -190,7 +191,8 @@ const SchedulerDialog = ({
|
|||||||
|
|
||||||
const handleDOWChange = useCallback(
|
const handleDOWChange = useCallback(
|
||||||
(_event: React.SyntheticEvent<HTMLElement>, flags: string[]) => {
|
(_event: React.SyntheticEvent<HTMLElement>, flags: string[]) => {
|
||||||
const newFlags = getFlagDOWnumber(flags);
|
const newFlags =
|
||||||
|
getFlagDOWnumber(flags) === 0 ? FLAG_ALL_DAYS : getFlagDOWnumber(flags);
|
||||||
setEditItem((prev) => ({ ...prev, flags: newFlags }));
|
setEditItem((prev) => ({ ...prev, flags: newFlags }));
|
||||||
},
|
},
|
||||||
[getFlagDOWnumber]
|
[getFlagDOWnumber]
|
||||||
@@ -336,11 +338,13 @@ const SchedulerDialog = ({
|
|||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
/>
|
/>
|
||||||
{isTimerSchedule && (
|
{isTimerSchedule && (
|
||||||
<Box color="warning.main" ml={2} mt={4}>
|
<Typography
|
||||||
<Typography variant="body2">
|
sx={{ ml: 2, mt: 4 }}
|
||||||
|
color="warning"
|
||||||
|
variant="body2"
|
||||||
|
>
|
||||||
{LL.SCHEDULER_HELP_2()}
|
{LL.SCHEDULER_HELP_2()}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -389,7 +393,7 @@ const SchedulerDialog = ({
|
|||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{!creating && (
|
{!creating && (
|
||||||
<Box flexGrow={1}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<RemoveIcon />}
|
startIcon={<RemoveIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ const Sensors = () => {
|
|||||||
|
|
||||||
const addAnalogSensor = useCallback(() => {
|
const addAnalogSensor = useCallback(() => {
|
||||||
if (firstAvailableGPIO.current === undefined) {
|
if (firstAvailableGPIO.current === undefined) {
|
||||||
toast.error('No available GPIO found');
|
toast.error(LL.NO_GPIO());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCreating(true);
|
setCreating(true);
|
||||||
@@ -591,7 +591,14 @@ const Sensors = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{sensorData?.analog_enabled === true && me.admin && (
|
{sensorData?.analog_enabled === true && me.admin && (
|
||||||
<Box mt={2} display="flex" flexWrap="wrap" justifyContent="flex-end">
|
<Box
|
||||||
|
sx={{
|
||||||
|
mt: 2,
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@@ -23,7 +23,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
|||||||
import { ValidatedTextField } from 'components';
|
import { ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValue } from 'utils';
|
import { numberValue, updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import { AnalogType, AnalogTypeNames, DeviceValueUOM_s } from './types';
|
import { AnalogType, AnalogTypeNames, DeviceValueUOM_s } from './types';
|
||||||
import type { AnalogSensor } from './types';
|
import type { AnalogSensor } from './types';
|
||||||
@@ -172,7 +172,7 @@ const SensorsAnalogDialog = ({
|
|||||||
await validate(validator, editItem);
|
await validate(validator, editItem);
|
||||||
onSave(editItem);
|
onSave(editItem);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [validator, editItem, onSave]);
|
}, [validator, editItem, onSave]);
|
||||||
|
|
||||||
@@ -479,7 +479,7 @@ const SensorsAnalogDialog = ({
|
|||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
{fieldErrors && Object.keys(fieldErrors).length > 0 && (
|
{fieldErrors && Object.keys(fieldErrors).length > 0 && (
|
||||||
<Box mt={1}>
|
<Box sx={{ mt: 1 }}>
|
||||||
{Object.values(fieldErrors).map((errArr, idx) =>
|
{Object.values(fieldErrors).map((errArr, idx) =>
|
||||||
Array.isArray(errArr)
|
Array.isArray(errArr)
|
||||||
? errArr.map((err, j) => (
|
? errArr.map((err, j) => (
|
||||||
@@ -487,7 +487,7 @@ const SensorsAnalogDialog = ({
|
|||||||
key={`${idx}-${j}`}
|
key={`${idx}-${j}`}
|
||||||
color="error"
|
color="error"
|
||||||
variant="caption"
|
variant="caption"
|
||||||
display="block"
|
sx={{ display: 'block' }}
|
||||||
>
|
>
|
||||||
{err.message}
|
{err.message}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -498,7 +498,7 @@ const SensorsAnalogDialog = ({
|
|||||||
)}
|
)}
|
||||||
{editItem.s && (
|
{editItem.s && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Typography mt={1} color="warning.main" variant="body2">
|
<Typography sx={{ mt: 1 }} color="warning" variant="body2">
|
||||||
<WarningIcon
|
<WarningIcon
|
||||||
fontSize="small"
|
fontSize="small"
|
||||||
sx={{ mr: 1, verticalAlign: 'middle' }}
|
sx={{ mr: 1, verticalAlign: 'middle' }}
|
||||||
@@ -511,7 +511,7 @@ const SensorsAnalogDialog = ({
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{!creating && (
|
{!creating && (
|
||||||
<Box flexGrow={1} sx={{ '& button': { mt: 0 } }}>
|
<Box sx={{ flexGrow: 1, '& button': { mt: 0 } }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<RemoveIcon />}
|
startIcon={<RemoveIcon />}
|
||||||
disabled={editItem.s}
|
disabled={editItem.s}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
|||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from '@mui/icons-material/Done';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import {
|
import {
|
||||||
Box,
|
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
@@ -22,7 +21,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
|||||||
import { ValidatedTextField } from 'components';
|
import { ValidatedTextField } from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValue } from 'utils';
|
import { numberValue, updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import type { TemperatureSensor } from './types';
|
import type { TemperatureSensor } from './types';
|
||||||
|
|
||||||
@@ -85,7 +84,7 @@ const SensorsTemperatureDialog = ({
|
|||||||
await validate(validator, editItem);
|
await validate(validator, editItem);
|
||||||
onSave(editItem);
|
onSave(editItem);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [validator, editItem, onSave]);
|
}, [validator, editItem, onSave]);
|
||||||
|
|
||||||
@@ -111,11 +110,9 @@ const SensorsTemperatureDialog = ({
|
|||||||
<Dialog sx={dialogStyle} open={open} onClose={handleClose}>
|
<Dialog sx={dialogStyle} open={open} onClose={handleClose}>
|
||||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Box color="warning.main" mb={2}>
|
<Typography sx={{ mb: 2 }} color="warning" variant="body2">
|
||||||
<Typography variant="body2">
|
|
||||||
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
|
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
@@ -142,7 +139,7 @@ const SensorsTemperatureDialog = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
{editItem.s && (
|
{editItem.s && (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Typography mt={1} color="warning.main" variant="body2">
|
<Typography sx={{ mt: 1 }} color="warning" variant="body2">
|
||||||
<WarningIcon
|
<WarningIcon
|
||||||
fontSize="small"
|
fontSize="small"
|
||||||
sx={{ mr: 1, verticalAlign: 'middle' }}
|
sx={{ mr: 1, verticalAlign: 'middle' }}
|
||||||
|
|||||||
@@ -41,8 +41,12 @@ const UserProfileComponent = () => {
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
<Box mt={2} mb={2} display="flex" alignItems="center">
|
<Box sx={{ mt: 2, mb: 2, display: 'flex', alignItems: 'center' }}>
|
||||||
<Typography mr={2} variant="body1" align="center">
|
<Typography
|
||||||
|
sx={{ mr: 2, textAlign: 'center' }}
|
||||||
|
color="warning"
|
||||||
|
variant="body1"
|
||||||
|
>
|
||||||
{LL.LANGUAGE()}:
|
{LL.LANGUAGE()}:
|
||||||
</Typography>
|
</Typography>
|
||||||
<LanguageSelector />
|
<LanguageSelector />
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ export interface Settings {
|
|||||||
modbus_port: number;
|
modbus_port: number;
|
||||||
modbus_max_clients: number;
|
modbus_max_clients: number;
|
||||||
modbus_timeout: number;
|
modbus_timeout: number;
|
||||||
|
email_enabled: boolean;
|
||||||
|
email_ssl?: boolean;
|
||||||
|
email_starttls?: boolean;
|
||||||
|
email_server: string;
|
||||||
|
email_port: number;
|
||||||
|
email_login: string;
|
||||||
|
email_pass: string;
|
||||||
|
email_sender: string;
|
||||||
|
email_recp: string;
|
||||||
|
email_subject: string;
|
||||||
developer_mode: boolean;
|
developer_mode: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +206,7 @@ export enum DeviceValueUOM {
|
|||||||
MBAR,
|
MBAR,
|
||||||
LH,
|
LH,
|
||||||
CTKWH,
|
CTKWH,
|
||||||
HZ
|
HERTZ
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeviceValueUOM_s = [
|
export const DeviceValueUOM_s = [
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import type { APSettingsType } from 'types';
|
import type { APSettingsType } from 'types';
|
||||||
import { APProvisionMode } from 'types';
|
import { APProvisionMode } from 'types';
|
||||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||||
import { createAPSettingsValidator, validate } from 'validators';
|
import { ValidationError, createAPSettingsValidator, validate } from 'validators';
|
||||||
|
|
||||||
export const isAPEnabled = ({ provision_mode }: APSettingsType) =>
|
export const isAPEnabled = ({ provision_mode }: APSettingsType) =>
|
||||||
provision_mode === APProvisionMode.AP_MODE_ALWAYS ||
|
provision_mode === APProvisionMode.AP_MODE_ALWAYS ||
|
||||||
@@ -86,7 +86,7 @@ const APSettings = () => {
|
|||||||
await validate(createAPSettingsValidator(data), data);
|
await validate(createAPSettingsValidator(data), data);
|
||||||
await saveData();
|
await saveData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [data, saveData]);
|
}, [data, saveData]);
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,13 @@ import {
|
|||||||
FormLoader,
|
FormLoader,
|
||||||
MessageBox,
|
MessageBox,
|
||||||
SectionContent,
|
SectionContent,
|
||||||
|
ValidatedPasswordField,
|
||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
import { API, getBoardProfile, readSettings, writeSettings } from '../../api/app';
|
import { API, getBoardProfile, readSettings, writeSettings } from '../../api/app';
|
||||||
import { BOARD_PROFILES } from '../main/types';
|
import { BOARD_PROFILES } from '../main/types';
|
||||||
@@ -153,7 +154,7 @@ const ApplicationSettings = () => {
|
|||||||
setFieldErrors(undefined);
|
setFieldErrors(undefined);
|
||||||
await validate(createSettingsValidator(data), data);
|
await validate(createSettingsValidator(data), data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
} finally {
|
} finally {
|
||||||
await saveData();
|
await saveData();
|
||||||
}
|
}
|
||||||
@@ -351,6 +352,156 @@ const ApplicationSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
<Typography color="secondary">eMail</Typography>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_enabled}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_enabled"
|
||||||
|
disabled={!hardwareData.psram}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<Typography color={!hardwareData.psram ? 'grey' : 'default'}>
|
||||||
|
Enable eMail notification
|
||||||
|
{!hardwareData.psram && (
|
||||||
|
<Typography variant="caption">
|
||||||
|
({LL.IS_REQUIRED('PSRAM')})
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{data.email_enabled && (
|
||||||
|
<>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
direction="row"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="flex-start"
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_server"
|
||||||
|
label="SMTP Server"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_server}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
name="email_port"
|
||||||
|
variant="outlined"
|
||||||
|
label="Port"
|
||||||
|
value={numberValue(data.email_port)}
|
||||||
|
type="number"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={4} mt={!data.email_ssl && !data.email_starttls ? 0 : 3}>
|
||||||
|
{!data.email_starttls && (
|
||||||
|
<BlockFormControlLabel
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_ssl}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_ssl"
|
||||||
|
disabled={
|
||||||
|
data.email_starttls || data.email_ssl === undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="SSL/TLS"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!data.email_ssl && (
|
||||||
|
<BlockFormControlLabel
|
||||||
|
sx={{ width: '12ch' }}
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={data.email_starttls}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
name="email_starttls"
|
||||||
|
disabled={
|
||||||
|
data.email_ssl || data.email_starttls === undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="STARTTLS"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_login"
|
||||||
|
label="Login"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_login}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedPasswordField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_pass"
|
||||||
|
label="Password"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_pass}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={2} rowSpacing={0}>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_sender"
|
||||||
|
label="From"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_sender}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_recp"
|
||||||
|
label="To"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_recp}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors || {}}
|
||||||
|
name="email_subject"
|
||||||
|
label="Subject"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.email_subject}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
||||||
{LL.SENSORS()}
|
{LL.SENSORS()}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -489,17 +640,25 @@ const ApplicationSettings = () => {
|
|||||||
name="board_profile"
|
name="board_profile"
|
||||||
label={LL.BOARD_PROFILE()}
|
label={LL.BOARD_PROFILE()}
|
||||||
value={data.board_profile}
|
value={data.board_profile}
|
||||||
disabled={processingBoard || hardwareData.model.startsWith('BBQKees')}
|
disabled={processingBoard}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={changeBoardProfile}
|
onChange={changeBoardProfile}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
select
|
select
|
||||||
>
|
>
|
||||||
{boardProfileItems}
|
{hardwareData.model.startsWith('BBQKees') ? (
|
||||||
<Divider />
|
<MenuItem key={hardwareData.board} value={hardwareData.board}>
|
||||||
|
{BOARD_PROFILES[hardwareData.board as BoardProfileKey]}
|
||||||
|
</MenuItem>
|
||||||
|
) : (
|
||||||
|
boardProfileItems
|
||||||
|
)}
|
||||||
|
{(data.board_profile === 'CUSTOM' || data.developer_mode) && <Divider />}
|
||||||
|
{(data.board_profile === 'CUSTOM' || data.developer_mode) && (
|
||||||
<MenuItem key={'CUSTOM'} value={'CUSTOM'}>
|
<MenuItem key={'CUSTOM'} value={'CUSTOM'}>
|
||||||
{LL.CUSTOM()}…
|
{LL.CUSTOM()}…
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
)}
|
||||||
</TextField>
|
</TextField>
|
||||||
{data.board_profile === 'CUSTOM' && (
|
{data.board_profile === 'CUSTOM' && (
|
||||||
<>
|
<>
|
||||||
@@ -763,7 +922,7 @@ const ApplicationSettings = () => {
|
|||||||
label={LL.REMOTE_TIMEOUT_EN()}
|
label={LL.REMOTE_TIMEOUT_EN()}
|
||||||
/>
|
/>
|
||||||
{data.remote_timeout_en && (
|
{data.remote_timeout_en && (
|
||||||
<Box mt={2}>
|
<Box sx={{ mt: 2 }}>
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
fieldErrors={fieldErrors || {}}
|
fieldErrors={fieldErrors || {}}
|
||||||
name="remote_timeout"
|
name="remote_timeout"
|
||||||
@@ -896,10 +1055,12 @@ const ApplicationSettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return restarting ? (
|
||||||
|
<SystemMonitor />
|
||||||
|
) : (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <SystemMonitor /> : content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import { Box, Button, Grid, Typography } from '@mui/material';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
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';
|
||||||
|
|
||||||
|
import { dialogStyle } from '@/CustomTheme';
|
||||||
import { useRequest } from 'alova/client';
|
import { useRequest } from 'alova/client';
|
||||||
import type { APIcall } from 'app/main/types';
|
import type { APIcall } from 'app/main/types';
|
||||||
import SystemMonitor from 'app/status/SystemMonitor';
|
import SystemMonitor from 'app/status/SystemMonitor';
|
||||||
@@ -19,16 +30,11 @@ import {
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { saveFile } from 'utils';
|
import { saveFile } from 'utils';
|
||||||
|
|
||||||
interface DownloadButton {
|
|
||||||
key: string;
|
|
||||||
type: string;
|
|
||||||
label: string | number;
|
|
||||||
isGridButton: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DownloadUpload = () => {
|
const DownloadUpload = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
const [confirmBackup, setConfirmBackup] = useState<boolean>(false);
|
||||||
|
|
||||||
const [restarting, setRestarting] = useState<boolean>(false);
|
const [restarting, setRestarting] = useState<boolean>(false);
|
||||||
|
|
||||||
const { send: sendExportData } = useRequest(
|
const { send: sendExportData } = useRequest(
|
||||||
@@ -63,45 +69,50 @@ const DownloadUpload = () => {
|
|||||||
|
|
||||||
useLayoutTitle(LL.DOWNLOAD_UPLOAD());
|
useLayoutTitle(LL.DOWNLOAD_UPLOAD());
|
||||||
|
|
||||||
const downloadButtons: DownloadButton[] = useMemo(
|
const handleCloseBackupDialog = useCallback(() => {
|
||||||
() => [
|
setConfirmBackup(false);
|
||||||
{
|
}, []);
|
||||||
key: 'settings',
|
|
||||||
type: 'settings',
|
const renderBackupDialog = useMemo(
|
||||||
label: LL.SETTINGS_OF(LL.APPLICATION()),
|
() => (
|
||||||
isGridButton: true
|
<Dialog
|
||||||
},
|
sx={dialogStyle}
|
||||||
{
|
open={confirmBackup}
|
||||||
key: 'customizations',
|
onClose={handleCloseBackupDialog}
|
||||||
type: 'customizations',
|
>
|
||||||
label: LL.CUSTOMIZATIONS(),
|
<DialogTitle>{LL.DOWNLOAD_SYSTEM_BACKUP()}</DialogTitle>
|
||||||
isGridButton: true
|
<DialogContent dividers>
|
||||||
},
|
<WarningIcon color="warning" sx={{ fontSize: 18 }} />
|
||||||
{
|
|
||||||
key: 'entities',
|
{LL.WARNING_SYSTEM_BACKUP()}
|
||||||
type: 'entities',
|
</DialogContent>
|
||||||
label: LL.CUSTOM_ENTITIES(0),
|
<DialogActions>
|
||||||
isGridButton: true
|
<Button
|
||||||
},
|
startIcon={<CancelIcon />}
|
||||||
{
|
variant="outlined"
|
||||||
key: 'schedule',
|
onClick={handleCloseBackupDialog}
|
||||||
type: 'schedule',
|
color="secondary"
|
||||||
label: LL.SCHEDULE(0),
|
>
|
||||||
isGridButton: true
|
{LL.CANCEL()}
|
||||||
},
|
</Button>
|
||||||
{
|
<Button
|
||||||
key: 'allvalues',
|
startIcon={<DownloadIcon />}
|
||||||
type: 'allvalues',
|
variant="outlined"
|
||||||
label: LL.ALLVALUES(),
|
onClick={() => handleDownload('systembackup')()}
|
||||||
isGridButton: false
|
color="primary"
|
||||||
}
|
>
|
||||||
],
|
{LL.DOWNLOAD(0)}
|
||||||
[LL]
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
),
|
||||||
|
[confirmBackup, handleCloseBackupDialog, LL]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDownload = useCallback(
|
const handleDownload = useCallback(
|
||||||
(type: string) => () => {
|
(type: string) => () => {
|
||||||
void sendExportData(type);
|
void sendExportData(type);
|
||||||
|
setConfirmBackup(false);
|
||||||
},
|
},
|
||||||
[sendExportData]
|
[sendExportData]
|
||||||
);
|
);
|
||||||
@@ -118,58 +129,57 @@ const DownloadUpload = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gridButtons = downloadButtons.filter((btn) => btn.isGridButton);
|
|
||||||
const standaloneButton = downloadButtons.find((btn) => !btn.isGridButton);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
|
{renderBackupDialog}
|
||||||
|
|
||||||
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
||||||
{LL.DOWNLOAD(0)}
|
{LL.DOWNLOAD(0)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography mb={1} variant="body1" color="warning">
|
<Grid
|
||||||
{LL.DOWNLOAD_SETTINGS_TEXT()}.
|
container
|
||||||
|
spacing={2}
|
||||||
|
sx={{
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body1" color="warning">
|
||||||
|
{LL.DOWNLOAD_SETTINGS_TEXT()}:
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{gridButtons.map((button) => (
|
|
||||||
<Grid key={button.key}>
|
|
||||||
<Button
|
<Button
|
||||||
startIcon={<DownloadIcon />}
|
startIcon={<DownloadIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleDownload(button.type)}
|
onClick={() => setConfirmBackup(true)}
|
||||||
>
|
>
|
||||||
{button.label}
|
{LL.DOWNLOAD_SYSTEM_BACKUP()}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Typography mt={2} mb={1} variant="body1" color="warning">
|
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}>
|
||||||
{LL.DOWNLOAD_SETTINGS_TEXT2()}.
|
<Typography variant="body1" color="warning">
|
||||||
|
{LL.DOWNLOAD_SETTINGS_TEXT2()}:
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{standaloneButton && (
|
|
||||||
<Button
|
<Button
|
||||||
startIcon={<DownloadIcon />}
|
startIcon={<DownloadIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleDownload(standaloneButton.type)}
|
onClick={handleDownload('allvalues')}
|
||||||
>
|
>
|
||||||
{standaloneButton.label}
|
{LL.ALLVALUES()}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</Grid>
|
||||||
|
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
{LL.UPLOAD()}
|
{LL.UPLOAD()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box color="warning.main" sx={{ pb: 2 }}>
|
<Typography sx={{ pb: 2 }} color="warning" variant="body1">
|
||||||
<Typography variant="body1">{LL.UPLOAD_TEXT()}.</Typography>
|
{LL.UPLOAD_TEXT()}:
|
||||||
</Box>
|
</Typography>
|
||||||
|
|
||||||
<SingleUpload text={LL.UPLOAD_DRAG()} doRestart={doRestart} />
|
<SingleUpload doRestart={doRestart} />
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { MqttSettingsType } from 'types';
|
import type { MqttSettingsType } from 'types';
|
||||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||||
import { createMqttSettingsValidator, validate } from 'validators';
|
import { ValidationError, createMqttSettingsValidator, validate } from 'validators';
|
||||||
|
|
||||||
import { callAction } from '../../api/app';
|
import { callAction } from '../../api/app';
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ const MqttSettings = () => {
|
|||||||
await validate(createMqttSettingsValidator(data), data);
|
await validate(createMqttSettingsValidator(data), data);
|
||||||
await saveData();
|
await saveData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [data, saveData]);
|
}, [data, saveData]);
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ const MqttSettings = () => {
|
|||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<>
|
<>
|
||||||
<Box display="flex" gap={2} mb={1}>
|
<Box sx={{ display: 'flex', gap: 2, mb: 1 }}>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -345,7 +345,7 @@ const MqttSettings = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid container spacing={2} rowSpacing={0}>
|
{/* <Grid container spacing={2} rowSpacing={0}> */}
|
||||||
<Grid>
|
<Grid>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={
|
control={
|
||||||
@@ -411,9 +411,25 @@ const MqttSettings = () => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
<Grid>
|
||||||
|
{data.discovery_type === 0 && (
|
||||||
|
<TextField
|
||||||
|
name="ha_number_mode"
|
||||||
|
label={LL.MQTT_INPUT_NUMBER_FORMAT()}
|
||||||
|
value={data.ha_number_mode}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
sx={{ width: '20ch' }}
|
||||||
|
margin="normal"
|
||||||
|
select
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>Box</MenuItem>
|
||||||
|
<MenuItem value={1}>Slider</MenuItem>
|
||||||
|
</TextField>
|
||||||
)}
|
)}
|
||||||
</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>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { NTPSettingsType, Time } from 'types';
|
import type { NTPSettingsType, Time } from 'types';
|
||||||
import { formatLocalDateTime, updateValueDirty, useRest } from 'utils';
|
import { formatLocalDateTime, updateValueDirty, useRest } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
|
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
|
||||||
|
|
||||||
import { TIME_ZONES, selectedTimeZone, useTimeZoneSelectItems } from './TZ';
|
import { TIME_ZONES, selectedTimeZone, useTimeZoneSelectItems } from './TZ';
|
||||||
@@ -133,7 +133,7 @@ const NTPSettings = () => {
|
|||||||
await validate(NTP_SETTINGS_VALIDATOR, data);
|
await validate(NTP_SETTINGS_VALIDATOR, data);
|
||||||
await saveData();
|
await saveData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [data, saveData]);
|
}, [data, saveData]);
|
||||||
|
|
||||||
@@ -193,9 +193,9 @@ const NTPSettings = () => {
|
|||||||
{timeZoneItems}
|
{timeZoneItems}
|
||||||
</ValidatedTextField>
|
</ValidatedTextField>
|
||||||
|
|
||||||
<Box display="flex" flexWrap="wrap">
|
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
{!data.enabled && !dirtyFlags.length && (
|
{!data.enabled && !dirtyFlags.length && (
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
onClick={openSetTime}
|
onClick={openSetTime}
|
||||||
@@ -259,9 +259,9 @@ const NTPSettings = () => {
|
|||||||
<Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}>
|
<Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}>
|
||||||
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
|
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>
|
<Typography color="warning" variant="body2">
|
||||||
<Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography>
|
{LL.SET_TIME_TEXT()}
|
||||||
</Box>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
label={LL.LOCAL_TIME(0)}
|
label={LL.LOCAL_TIME(0)}
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
|||||||
@@ -156,11 +156,13 @@ const Settings = () => {
|
|||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
mt={2}
|
sx={{
|
||||||
display="flex"
|
mt: 2,
|
||||||
justifyContent="flex-end"
|
display: 'flex',
|
||||||
flexWrap="nowrap"
|
justifyContent: 'flex-end',
|
||||||
whiteSpace="nowrap"
|
flexWrap: 'nowrap',
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<SettingsBackupRestoreIcon />}
|
startIcon={<SettingsBackupRestoreIcon />}
|
||||||
@@ -182,7 +184,7 @@ const Settings = () => {
|
|||||||
restarting
|
restarting
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>;
|
return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import {
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { NetworkSettingsType } from 'types';
|
import type { NetworkSettingsType } from 'types';
|
||||||
import { updateValueDirty, useRest } from 'utils';
|
import { updateValueDirty, useRest } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
import { createNetworkSettingsValidator } from 'validators/network';
|
import { createNetworkSettingsValidator } from 'validators/network';
|
||||||
|
|
||||||
import SystemMonitor from '../../status/SystemMonitor';
|
import SystemMonitor from '../../status/SystemMonitor';
|
||||||
@@ -116,7 +116,7 @@ const NetworkSettings = () => {
|
|||||||
await validate(createNetworkSettingsValidator(data), data);
|
await validate(createNetworkSettingsValidator(data), data);
|
||||||
await saveData();
|
await saveData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
deselectNetwork();
|
deselectNetwork();
|
||||||
}, [data, saveData, deselectNetwork]);
|
}, [data, saveData, deselectNetwork]);
|
||||||
@@ -397,10 +397,12 @@ const NetworkSettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return restarting ? (
|
||||||
|
<SystemMonitor />
|
||||||
|
) : (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <SystemMonitor /> : content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,19 +54,27 @@ const GenerateToken = ({ username, onClose }: GenerateTokenProps) => {
|
|||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
{token ? (
|
{token ? (
|
||||||
<>
|
<>
|
||||||
<MessageBox message={LL.ACCESS_TOKEN_TEXT()} level="info" my={2} />
|
<MessageBox
|
||||||
<Box mt={2} mb={2}>
|
message={LL.ACCESS_TOKEN_TEXT()}
|
||||||
|
level="info"
|
||||||
|
sx={{ mt: 2, mb: 2 }}
|
||||||
|
/>
|
||||||
|
<Box sx={{ mt: 2, mb: 2 }}>
|
||||||
<TextField
|
<TextField
|
||||||
label="Token"
|
label="Token"
|
||||||
multiline
|
multiline
|
||||||
value={token.token}
|
value={token.token}
|
||||||
fullWidth
|
fullWidth
|
||||||
contentEditable={false}
|
slotProps={{
|
||||||
|
input: {
|
||||||
|
readOnly: true
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Box m={4} textAlign="center">
|
<Box sx={{ m: 4, textAlign: 'center' }}>
|
||||||
<LinearProgress />
|
<LinearProgress />
|
||||||
<Typography variant="h6">{LL.GENERATING_TOKEN()}…</Typography>
|
<Typography variant="h6">{LL.GENERATING_TOKEN()}…</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -240,12 +240,16 @@ const ManageUsers = () => {
|
|||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
{noAdminConfigured() && (
|
{noAdminConfigured() && (
|
||||||
<MessageBox level="warning" message={LL.USER_WARNING()} my={2} />
|
<MessageBox
|
||||||
|
level="warning"
|
||||||
|
message={LL.USER_WARNING()}
|
||||||
|
sx={{ mt: 2, mb: 2 }}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box display="flex" flexWrap="wrap">
|
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
{changed !== 0 && (
|
{changed !== 0 && (
|
||||||
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
|
<Box sx={{ flexGrow: 1, '& button': { mt: 2 } }}>
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
@@ -270,7 +274,7 @@ const ManageUsers = () => {
|
|||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<PersonAddIcon />}
|
startIcon={<PersonAddIcon />}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { AuthenticatedContext } from 'contexts/authentication';
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { SecuritySettingsType } from 'types';
|
import type { SecuritySettingsType } from 'types';
|
||||||
import { updateValueDirty, useRest } from 'utils';
|
import { updateValueDirty, useRest } from 'utils';
|
||||||
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
|
import { SECURITY_SETTINGS_VALIDATOR, ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
const SecuritySettings = () => {
|
const SecuritySettings = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
@@ -58,7 +58,7 @@ const SecuritySettings = () => {
|
|||||||
await saveData();
|
await saveData();
|
||||||
await authenticatedContext.refresh();
|
await authenticatedContext.refresh();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}, [data, saveData, authenticatedContext]);
|
}, [data, saveData, authenticatedContext]);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import type { UserType } from 'types';
|
import type { UserType } from 'types';
|
||||||
import { updateValue } from 'utils';
|
import { updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { ValidationError, validate } from 'validators';
|
||||||
|
|
||||||
interface UserFormProps {
|
interface UserFormProps {
|
||||||
creating: boolean;
|
creating: boolean;
|
||||||
@@ -69,7 +69,7 @@ const User: FC<UserFormProps> = ({
|
|||||||
await validate(validator, user);
|
await validate(validator, user);
|
||||||
onDoneEditing();
|
onDoneEditing();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldErrors(error as ValidateFieldsError);
|
setFieldErrors((error as ValidationError).fieldErrors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [user, validator, onDoneEditing]);
|
}, [user, validator, onDoneEditing]);
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ const SystemStatus = () => {
|
|||||||
renderRestartDialog
|
renderRestartDialog
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>;
|
return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SystemStatus;
|
export default SystemStatus;
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ 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 MAX_LOG_ENTRIES = 1000; // Limit log entries to prevent memory issues
|
|
||||||
|
|
||||||
const TextColors: Record<LogLevel, string> = {
|
const TextColors: Record<LogLevel, string> = {
|
||||||
[LogLevel.ERROR]: '#ff0000', // red
|
[LogLevel.ERROR]: '#ff0000', // red
|
||||||
[LogLevel.WARNING]: '#ff0000', // red
|
[LogLevel.WARNING]: '#ff0000', // red
|
||||||
@@ -200,10 +198,6 @@ const SystemLog = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const newLog = [...log, logentry];
|
const newLog = [...log, logentry];
|
||||||
// Limit log entries to prevent memory issues - only slice when necessary
|
|
||||||
if (newLog.length > MAX_LOG_ENTRIES) {
|
|
||||||
return newLog.slice(-MAX_LOG_ENTRIES);
|
|
||||||
}
|
|
||||||
return newLog;
|
return newLog;
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -272,7 +266,7 @@ const SystemLog = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Grid container spacing={2} alignItems="center">
|
<Grid container spacing={2} sx={{ alignItems: 'center' }}>
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextField
|
<TextField
|
||||||
name="level"
|
name="level"
|
||||||
@@ -308,6 +302,8 @@ const SystemLog = () => {
|
|||||||
<MenuItem value={50}>50</MenuItem>
|
<MenuItem value={50}>50</MenuItem>
|
||||||
<MenuItem value={75}>75</MenuItem>
|
<MenuItem value={75}>75</MenuItem>
|
||||||
<MenuItem value={100}>100</MenuItem>
|
<MenuItem value={100}>100</MenuItem>
|
||||||
|
<MenuItem value={500}>500</MenuItem>
|
||||||
|
<MenuItem value={1000}>1000</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -60,18 +60,16 @@ const SystemMonitor = () => {
|
|||||||
const { statusMessage, isUploading, progressValue } = useMemo(() => {
|
const { statusMessage, isUploading, progressValue } = useMemo(() => {
|
||||||
const status = data?.status;
|
const status = data?.status;
|
||||||
|
|
||||||
let message = '';
|
const message =
|
||||||
if (status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING) {
|
status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING
|
||||||
message = LL.WAIT_FIRMWARE();
|
? LL.WAIT_FIRMWARE()
|
||||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART) {
|
: status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART
|
||||||
message = LL.APPLICATION_RESTARTING();
|
? LL.APPLICATION_RESTARTING()
|
||||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_NORMAL) {
|
: status === SystemStatusCodes.SYSTEM_STATUS_NORMAL
|
||||||
message = LL.RESTARTING_PRE();
|
? LL.RESTARTING_PRE()
|
||||||
} else if (status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD) {
|
: status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD
|
||||||
message = 'Upload Failed';
|
? 'Upload Failed'
|
||||||
} else {
|
: LL.RESTARTING_POST();
|
||||||
message = LL.RESTARTING_POST();
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploading =
|
const uploading =
|
||||||
status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING;
|
status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING;
|
||||||
@@ -103,8 +101,8 @@ const SystemMonitor = () => {
|
|||||||
height: '100vh',
|
height: '100vh',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center'
|
||||||
backdropFilter: 'blur(8px)'
|
// backdropFilter: 'blur(8px)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@@ -120,17 +118,15 @@ const SystemMonitor = () => {
|
|||||||
p: 3
|
p: 3
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box display="flex" alignItems="center" flexDirection="column">
|
<Box sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
|
||||||
<img
|
<img
|
||||||
src="/app/icon.png"
|
src="/app/icon.png"
|
||||||
alt="EMS-ESP"
|
alt="EMS-ESP"
|
||||||
style={{ width: '40px', height: '40px', marginBottom: '16px' }}
|
style={{ width: '40px', height: '40px', marginBottom: '16px' }}
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
color="secondary"
|
sx={{ color: 'secondary', fontWeight: 400, textAlign: 'center' }}
|
||||||
variant="h6"
|
variant="h6"
|
||||||
fontWeight={400}
|
|
||||||
textAlign="center"
|
|
||||||
>
|
>
|
||||||
{statusMessage}
|
{statusMessage}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -150,11 +146,14 @@ const SystemMonitor = () => {
|
|||||||
</MessageBox>
|
</MessageBox>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Typography mt={2} variant="h6" fontWeight={400} textAlign="center">
|
<Typography
|
||||||
|
sx={{ mt: 2, fontWeight: 400, textAlign: 'center' }}
|
||||||
|
variant="h6"
|
||||||
|
>
|
||||||
{LL.PLEASE_WAIT()}…
|
{LL.PLEASE_WAIT()}…
|
||||||
</Typography>
|
</Typography>
|
||||||
{isUploading && (
|
{isUploading && (
|
||||||
<Box width="100%" pl={2} pr={2} py={2}>
|
<Box sx={{ width: '100%', pl: 2, pr: 2, py: 2 }}>
|
||||||
<LinearProgressWithLabel value={progressValue} />
|
<LinearProgressWithLabel value={progressValue} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { Link } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
@@ -24,7 +25,6 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
Link,
|
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
@@ -274,6 +274,7 @@ const InstallDialog = memo(
|
|||||||
fetchDevVersion,
|
fetchDevVersion,
|
||||||
latestVersion,
|
latestVersion,
|
||||||
latestDevVersion,
|
latestDevVersion,
|
||||||
|
upgradeImportantMessageType,
|
||||||
downloadOnly,
|
downloadOnly,
|
||||||
platform,
|
platform,
|
||||||
LL,
|
LL,
|
||||||
@@ -284,6 +285,7 @@ const InstallDialog = memo(
|
|||||||
fetchDevVersion: boolean;
|
fetchDevVersion: boolean;
|
||||||
latestVersion?: VersionInfo;
|
latestVersion?: VersionInfo;
|
||||||
latestDevVersion?: VersionInfo;
|
latestDevVersion?: VersionInfo;
|
||||||
|
upgradeImportantMessageType: number;
|
||||||
downloadOnly: boolean;
|
downloadOnly: boolean;
|
||||||
platform: string;
|
platform: string;
|
||||||
LL: TranslationFunctions;
|
LL: TranslationFunctions;
|
||||||
@@ -307,12 +309,24 @@ const InstallDialog = memo(
|
|||||||
{`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`}
|
{`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Typography mb={2}>
|
<Typography sx={{ mb: 2 }}>
|
||||||
{LL.INSTALL_VERSION(
|
{LL.INSTALL_VERSION(
|
||||||
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
||||||
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||||
)}
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
{upgradeImportantMessageType === 1 && LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
||||||
|
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||||
|
<Typography sx={{ mt: 2 }}>
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
||||||
|
style={{ color: 'lightblue' }}
|
||||||
|
>
|
||||||
|
{LL.ONLINE_HELP()}
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
@@ -329,7 +343,12 @@ const InstallDialog = memo(
|
|||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<Link underline="none" target="_blank" href={binURL} color="primary">
|
<Link
|
||||||
|
to={binURL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
style={{ color: 'lightblue', textDecoration: 'none' }}
|
||||||
|
>
|
||||||
{LL.DOWNLOAD(0)}
|
{LL.DOWNLOAD(0)}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -371,7 +390,9 @@ const InstallPartitionDialog = memo(
|
|||||||
{LL.INSTALL()} {LL.STORED_VERSIONS()}
|
{LL.INSTALL()} {LL.STORED_VERSIONS()}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Typography mb={2}>{LL.INSTALL_VERSION(LL.INSTALL(), version)}</Typography>
|
<Typography sx={{ mb: 2 }}>
|
||||||
|
{LL.INSTALL_VERSION(LL.INSTALL(), version)}
|
||||||
|
</Typography>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
@@ -467,6 +488,26 @@ const Version = () => {
|
|||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
|
||||||
|
useState<number>(0);
|
||||||
|
|
||||||
|
const { send: checkUpgradeImportantMessages } = useRequest(
|
||||||
|
(version: string) =>
|
||||||
|
callAction({ action: 'upgradeImportantMessages', param: version }),
|
||||||
|
{
|
||||||
|
immediate: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onSuccess((event) => {
|
||||||
|
const upgradeImportantMessageType_n = (
|
||||||
|
event.data as { upgradeImportantMessageType: number }
|
||||||
|
).upgradeImportantMessageType;
|
||||||
|
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
|
||||||
|
})
|
||||||
|
.onError((error) => {
|
||||||
|
toast.error(String(error.error?.message || 'An error occurred'));
|
||||||
|
});
|
||||||
|
|
||||||
// Memoized values
|
// Memoized values
|
||||||
const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]);
|
const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]);
|
||||||
|
|
||||||
@@ -532,10 +573,16 @@ const Version = () => {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const showFirmwareDialog = useCallback((useDevVersion: boolean) => {
|
const showFirmwareDialog = useCallback(
|
||||||
|
(useDevVersion: boolean) => {
|
||||||
setFetchDevVersion(useDevVersion);
|
setFetchDevVersion(useDevVersion);
|
||||||
|
void checkUpgradeImportantMessages(
|
||||||
|
useDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||||
|
);
|
||||||
setOpenInstallDialog(true);
|
setOpenInstallDialog(true);
|
||||||
}, []);
|
},
|
||||||
|
[latestDevVersion, latestVersion, fetchDevVersion]
|
||||||
|
);
|
||||||
|
|
||||||
const closeInstallDialog = useCallback(() => {
|
const closeInstallDialog = useCallback(() => {
|
||||||
setOpenInstallDialog(false);
|
setOpenInstallDialog(false);
|
||||||
@@ -637,8 +684,8 @@ const Version = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box p={2} border="1px solid grey" borderRadius={2}>
|
<Box sx={{ p: 2, border: '1px solid #565656', borderRadius: 2 }}>
|
||||||
<Typography mb={1} variant="h6" color="primary">
|
<Typography sx={{ mb: 1 }} variant="h6" color="primary">
|
||||||
{LL.THIS_VERSION()}
|
{LL.THIS_VERSION()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -703,7 +750,7 @@ const Version = () => {
|
|||||||
|
|
||||||
{internetLive ? (
|
{internetLive ? (
|
||||||
<>
|
<>
|
||||||
<Typography mt={4} mb={1} variant="h6" color="primary">
|
<Typography sx={{ mt: 4, mb: 1 }} variant="h6" color="primary">
|
||||||
{LL.AVAILABLE_VERSION()}
|
{LL.AVAILABLE_VERSION()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -725,7 +772,7 @@ const Version = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 8, md: 10 }}>
|
<Grid size={{ xs: 8, md: 10 }}>
|
||||||
{otherPartitions.map((partition) => (
|
{otherPartitions.map((partition) => (
|
||||||
<Typography key={partition.partition} mb={1}>
|
<Typography key={partition.partition} sx={{ mb: 1 }}>
|
||||||
{partition.version}
|
{partition.version}
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -791,7 +838,7 @@ const Version = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Typography mt={2} color="warning">
|
<Typography sx={{ mt: 2 }} color="warning">
|
||||||
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
|
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
|
||||||
{LL.INTERNET_CONNECTION_REQUIRED()}
|
{LL.INTERNET_CONNECTION_REQUIRED()}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -815,6 +862,7 @@ const Version = () => {
|
|||||||
fetchDevVersion={fetchDevVersion}
|
fetchDevVersion={fetchDevVersion}
|
||||||
latestVersion={latestVersion}
|
latestVersion={latestVersion}
|
||||||
latestDevVersion={latestDevVersion}
|
latestDevVersion={latestDevVersion}
|
||||||
|
upgradeImportantMessageType={upgradeImportantMessageType}
|
||||||
downloadOnly={downloadOnly}
|
downloadOnly={downloadOnly}
|
||||||
platform={platform}
|
platform={platform}
|
||||||
LL={LL}
|
LL={LL}
|
||||||
@@ -832,7 +880,7 @@ const Version = () => {
|
|||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
{LL.UPLOAD()}
|
{LL.UPLOAD()}
|
||||||
</Typography>
|
</Typography>
|
||||||
<SingleUpload text={LL.UPLOAD_DROP_TEXT()} doRestart={doRestart} />
|
<SingleUpload doRestart={doRestart} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -868,7 +916,7 @@ const Version = () => {
|
|||||||
installPartitionFirmware
|
installPartitionFirmware
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <SectionContent>{restarting ? <SystemMonitor /> : content}</SectionContent>;
|
return restarting ? <SystemMonitor /> : <SectionContent>{content}</SectionContent>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Version);
|
export default memo(Version);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { memo } from 'react';
|
import { type FC, type PropsWithChildren, 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 = memo<BoxProps>(({ children, ...rest }) => (
|
const ButtonRow: FC<PropsWithChildren<BoxProps>> = memo(({ children, ...rest }) => (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
'& button, & a, & .MuiCard-root': {
|
'& button, & a, & .MuiCard-root': {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type FC, memo, useMemo } from 'react';
|
import { type FC, type PropsWithChildren, memo, useMemo } from 'react';
|
||||||
|
|
||||||
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
|
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
@@ -12,6 +12,7 @@ type MessageBoxLevel = 'warning' | 'success' | 'info' | 'error';
|
|||||||
export interface MessageBoxProps extends BoxProps {
|
export interface MessageBoxProps extends BoxProps {
|
||||||
level: MessageBoxLevel;
|
level: MessageBoxLevel;
|
||||||
message?: string;
|
message?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LEVEL_ICONS: Record<MessageBoxLevel, React.ComponentType<SvgIconProps>> = {
|
const LEVEL_ICONS: Record<MessageBoxLevel, React.ComponentType<SvgIconProps>> = {
|
||||||
@@ -28,7 +29,7 @@ const LEVEL_PALETTE_PATHS: Record<MessageBoxLevel, string> = {
|
|||||||
error: 'error.dark'
|
error: 'error.dark'
|
||||||
};
|
};
|
||||||
|
|
||||||
const MessageBox: FC<MessageBoxProps> = ({
|
const MessageBox: FC<PropsWithChildren<MessageBoxProps>> = ({
|
||||||
level,
|
level,
|
||||||
message,
|
message,
|
||||||
sx,
|
sx,
|
||||||
@@ -52,12 +53,16 @@ const MessageBox: FC<MessageBoxProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
p={2}
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
borderRadius={1}
|
|
||||||
sx={{ backgroundColor, color: 'white', ...sx }}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderRadius: 1,
|
||||||
|
backgroundColor,
|
||||||
|
color: 'white',
|
||||||
|
p: 2,
|
||||||
|
...sx
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Icon />
|
<Icon />
|
||||||
{(message || children) && (
|
{(message || children) && (
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const LayoutDrawerComponent = ({ mobileOpen, onClose }: LayoutDrawerProps) => {
|
|||||||
() => (
|
() => (
|
||||||
<>
|
<>
|
||||||
<Toolbar disableGutters>
|
<Toolbar disableGutters>
|
||||||
<Box display="flex" alignItems="center" px={2}>
|
<Box sx={{ display: 'flex', alignItems: 'center', p: 2 }}>
|
||||||
<LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} />
|
<LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} />
|
||||||
<Typography variant="h6">{PROJECT_NAME}</Typography>
|
<Typography variant="h6">{PROJECT_NAME}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ const LayoutMenuComponent = () => {
|
|||||||
sx={{ my: 0 }}
|
sx={{ my: 0 }}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
primary: {
|
primary: {
|
||||||
fontWeight: '600',
|
sx: { fontWeight: 600, mb: '2px', color: 'lightblue' }
|
||||||
mb: '2px',
|
|
||||||
color: 'lightblue'
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -39,9 +39,8 @@ const LayoutMenuItemComponent = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
width: selected ? '4px' : '0px',
|
width: selected ? '3px' : '0px',
|
||||||
backgroundColor: '#90caf9',
|
backgroundColor: '#90caf9',
|
||||||
borderRadius: '0 2px 2px 0',
|
|
||||||
transition: 'width 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)'
|
transition: 'width 0.05s cubic-bezier(0.55, 0.085, 0.68, 0.53)'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -32,8 +32,16 @@ const FormLoaderComponent = ({ errorMessage, onRetry }: FormLoaderProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Box m={2} py={2} display="flex" alignItems="center" flexDirection="column">
|
<Box
|
||||||
<Box py={2}>
|
sx={{
|
||||||
|
m: 2,
|
||||||
|
py: 2,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ p: 2 }}>
|
||||||
<CircularProgress size={100} />
|
<CircularProgress size={100} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ const circularProgressStyles: SxProps<Theme> = (theme: Theme) => ({
|
|||||||
const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => {
|
const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
sx={{
|
||||||
alignItems="center"
|
display: 'flex',
|
||||||
justifyContent="center"
|
alignItems: 'center',
|
||||||
flexDirection="column"
|
justifyContent: 'center',
|
||||||
padding={2}
|
flexDirection: 'column',
|
||||||
height={height}
|
padding: 2,
|
||||||
|
height
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<CircularProgress sx={circularProgressStyles} size={100} />
|
<CircularProgress sx={circularProgressStyles} size={100} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// 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
|
// drag/drop 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 {
|
import {
|
||||||
type ChangeEvent,
|
type ChangeEvent,
|
||||||
type DragEvent,
|
type DragEvent,
|
||||||
@@ -6,12 +6,28 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
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, Typography, styled } from '@mui/material';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Typography,
|
||||||
|
styled
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { callAction } from 'api/app';
|
||||||
|
|
||||||
|
import { dialogStyle } from '@/CustomTheme';
|
||||||
|
import { useRequest } from 'alova/client';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
|
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
|
||||||
@@ -58,6 +74,29 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
|||||||
const [dragged, setDragged] = useState(false);
|
const [dragged, setDragged] = useState(false);
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false);
|
||||||
|
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
|
||||||
|
useState<number>(0);
|
||||||
|
|
||||||
|
const { send: checkUpgradeImportantMessages } = useRequest(
|
||||||
|
(version: string) =>
|
||||||
|
callAction({ action: 'upgradeImportantMessages', param: version }),
|
||||||
|
{
|
||||||
|
immediate: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.onSuccess((event) => {
|
||||||
|
const upgradeImportantMessageType_n = (
|
||||||
|
event.data as { upgradeImportantMessageType: number }
|
||||||
|
).upgradeImportantMessageType;
|
||||||
|
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
|
||||||
|
if (upgradeImportantMessageType_n === 0) {
|
||||||
|
onFileSelected(file);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onError((error) => {
|
||||||
|
toast.error(String(error.error?.message || 'An error occurred'));
|
||||||
|
});
|
||||||
|
|
||||||
const checkFileExtension = (file: File) => {
|
const checkFileExtension = (file: File) => {
|
||||||
const validExtensions = ['.json', '.bin', '.md5'];
|
const validExtensions = ['.json', '.bin', '.md5'];
|
||||||
@@ -97,9 +136,8 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
|||||||
|
|
||||||
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
|
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (file) {
|
void checkUpgradeImportantMessages(file?.name || '');
|
||||||
onFileSelected(file);
|
setShowUpgradeDialog(true);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBrowseClick = () => {
|
const handleBrowseClick = () => {
|
||||||
@@ -158,6 +196,56 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
|||||||
{LL.UPLOAD()}
|
{LL.UPLOAD()}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
{showUpgradeDialog && upgradeImportantMessageType > 0 && (
|
||||||
|
<Dialog
|
||||||
|
sx={dialogStyle}
|
||||||
|
open={showUpgradeDialog}
|
||||||
|
onClose={() => setShowUpgradeDialog(false)}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<WarningIcon
|
||||||
|
color="warning"
|
||||||
|
sx={{ fontSize: 18, verticalAlign: 'middle' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{LL.UPGRADE_IMPORTANT_MESSAGES()}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent dividers>
|
||||||
|
{upgradeImportantMessageType === 2 &&
|
||||||
|
LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||||
|
{upgradeImportantMessageType === 1 &&
|
||||||
|
LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
||||||
|
<Typography sx={{ mt: 2 }}>
|
||||||
|
<Link
|
||||||
|
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
style={{ color: 'lightblue' }}
|
||||||
|
>
|
||||||
|
{LL.ONLINE_HELP()}
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
startIcon={<CancelIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setShowUpgradeDialog(false)}
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
{LL.CANCEL()}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<UploadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => onFileSelected(file)}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{LL.UPLOAD()}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DocumentUploader>
|
</DocumentUploader>
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ import DragNdrop from './DragNdrop';
|
|||||||
import { LinearProgressWithLabel } from './LinearProgressWithLabel';
|
import { LinearProgressWithLabel } from './LinearProgressWithLabel';
|
||||||
|
|
||||||
interface SingleUploadProps {
|
interface SingleUploadProps {
|
||||||
text: string;
|
|
||||||
doRestart: () => void;
|
doRestart: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
const SingleUpload = ({ 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();
|
||||||
@@ -58,7 +57,7 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
|||||||
<>
|
<>
|
||||||
{isUploading ? (
|
{isUploading ? (
|
||||||
<>
|
<>
|
||||||
<Box width="100%" pl={2} pr={2}>
|
<Box sx={{ width: '100%', pl: 2, pr: 2 }}>
|
||||||
<LinearProgressWithLabel
|
<LinearProgressWithLabel
|
||||||
value={
|
value={
|
||||||
progress.total === 0 || progress.loaded === 0
|
progress.total === 0 || progress.loaded === 0
|
||||||
@@ -81,11 +80,11 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<DragNdrop text={text} onFileSelected={setFile} />
|
<DragNdrop text={LL.UPLOAD_DROP_TEXT()} onFileSelected={setFile} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{md5 && (
|
{md5 && (
|
||||||
<Box mt={2}>
|
<Box sx={{ mt: 2 }}>
|
||||||
<Typography variant="body2">{'MD5: ' + md5}</Typography>
|
<Typography variant="body2">{'MD5: ' + md5}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const cz: Translation = {
|
|||||||
BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti',
|
BUFFER_SIZE: 'Maximální velikost vyrovnávací paměti',
|
||||||
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',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechna data',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
|
||||||
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
|
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr',
|
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',
|
||||||
@@ -219,6 +220,7 @@ const cz: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Povolit MQTT Discovery',
|
MQTT_PUBLISH_TEXT_3: 'Povolit MQTT Discovery',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix pro Discovery témata',
|
MQTT_PUBLISH_TEXT_4: 'Prefix pro Discovery témata',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Typ Discovery',
|
MQTT_PUBLISH_TEXT_5: 'Typ Discovery',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Formát čísla',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Intervaly publikování',
|
MQTT_PUBLISH_INTERVALS: 'Intervaly publikování',
|
||||||
MQTT_INT_BOILER: 'Kotle a tepelná čerpadla',
|
MQTT_INT_BOILER: 'Kotle a tepelná čerpadla',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||||
@@ -348,15 +350,22 @@ const cz: Translation = {
|
|||||||
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
|
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
|
||||||
NO_DATA_2: 'pro jejich výběr.',
|
NO_DATA_2: 'pro jejich výběr.',
|
||||||
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
|
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
|
||||||
|
NO_GPIO: 'Nebylo nalezeno žádné volné GPIO',
|
||||||
THIS_VERSION: 'Tato verze',
|
THIS_VERSION: 'Tato verze',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Typ sestavení',
|
RELEASE_TYPE: 'Typ sestavení',
|
||||||
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',
|
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
|
||||||
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
|
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
|
||||||
NO_DATA: 'Žádná data',
|
NO_DATA: 'žádné údaje',
|
||||||
USER_PROFILE: 'Uživatelský profil',
|
USER_PROFILE: 'Uživatelský profil',
|
||||||
STORED_VERSIONS: 'Uložené verze'
|
STORED_VERSIONS: 'Uložené verze',
|
||||||
|
ONLINE_HELP: 'online nápověda',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovat důležité zprávy',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Tato aktualizace vyžaduje obnovení továrního nastavení. Ujistěte se, že nejprve stáhnete systémovou zálohu před pokračováním a poté nahrajte tento soubor po instalaci nové verze.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete se na novou hlavní verzi. Ujistěte se, že jste přečetli ChangeLog pro jakékoliv závažné změny.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Toto vytvoří zálohu vašich celých systémových konfigurací a nastavení. Všechna hesla budou v zálohovém souboru čitelná. Buďte opatrní při sdílení! Opravdu chcete pokračovat?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default cz;
|
export default cz;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const de: Translation = {
|
|||||||
BUFFER_SIZE: 'Max. Puffergröße',
|
BUFFER_SIZE: 'Max. Puffergröße',
|
||||||
COMPACT: 'Kompakte Darstellung',
|
COMPACT: 'Kompakte Darstellung',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
|
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Daten',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Systemsicherung',
|
||||||
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
|
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
|
||||||
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
|
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
|
||||||
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
|
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
|
||||||
@@ -219,6 +220,7 @@ const de: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery`',
|
MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery`',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery Typ',
|
MQTT_PUBLISH_TEXT_5: 'Discovery Typ',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Zahlenformat',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle',
|
MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle',
|
||||||
MQTT_INT_BOILER: 'Boiler und Wärmepumpen',
|
MQTT_INT_BOILER: 'Boiler und Wärmepumpen',
|
||||||
MQTT_INT_THERMOSTATS: 'Thermostate',
|
MQTT_INT_THERMOSTATS: 'Thermostate',
|
||||||
@@ -348,6 +350,7 @@ const de: Translation = {
|
|||||||
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.',
|
||||||
NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu',
|
NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu',
|
||||||
|
NO_GPIO: 'Keine freien GPIO gefunden',
|
||||||
THIS_VERSION: 'Diese Version',
|
THIS_VERSION: 'Diese Version',
|
||||||
PLATFORM: 'Plattform',
|
PLATFORM: 'Plattform',
|
||||||
RELEASE_TYPE: 'Release Typ',
|
RELEASE_TYPE: 'Release Typ',
|
||||||
@@ -356,7 +359,13 @@ const de: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
|
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
|
||||||
NO_DATA: 'Keine Daten',
|
NO_DATA: 'Keine Daten',
|
||||||
USER_PROFILE: 'Benutzerprofil',
|
USER_PROFILE: 'Benutzerprofil',
|
||||||
STORED_VERSIONS: 'Gespeicherte Versionen'
|
STORED_VERSIONS: 'Gespeicherte Versionen',
|
||||||
|
ONLINE_HELP: 'Online-Hilfe',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten aktualisieren',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Für diese Aktualisierung ist ein Werksreset erforderlich. Stellen Sie sicher, dass Sie zuerst eine Systemsicherung herunterladen, bevor Sie fortfahren, und laden Sie diese Datei dann nach der Installation der neuen Version hoch.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Sie aktualisieren auf eine neue Hauptversion. Stellen Sie sicher, dass Sie den ChangeLog für alle wichtigen Änderungen gelesen haben.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und Einstellungen erstellen. Alle Passwörter werden in dieser Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const en: Translation = {
|
|||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Export all data',
|
DOWNLOAD_SETTINGS_TEXT2: 'Export all values',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'System Backup',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||||
ERROR: 'Unexpected Error, please try again',
|
ERROR: 'Unexpected Error, please try again',
|
||||||
@@ -219,6 +220,7 @@ const en: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Enable MQTT Discovery',
|
MQTT_PUBLISH_TEXT_3: 'Enable MQTT Discovery',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix for the Discovery topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefix for the Discovery topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Input Number Fomat',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Publish Intervals',
|
MQTT_PUBLISH_INTERVALS: 'Publish Intervals',
|
||||||
MQTT_INT_BOILER: 'Boilers and Heat Pumps',
|
MQTT_INT_BOILER: 'Boilers and Heat Pumps',
|
||||||
MQTT_INT_THERMOSTATS: 'Thermostats',
|
MQTT_INT_THERMOSTATS: 'Thermostats',
|
||||||
@@ -348,6 +350,7 @@ const en: Translation = {
|
|||||||
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',
|
||||||
|
NO_GPIO: 'No available GPIO found',
|
||||||
THIS_VERSION: 'This Version',
|
THIS_VERSION: 'This Version',
|
||||||
PLATFORM: 'Platform',
|
PLATFORM: 'Platform',
|
||||||
RELEASE_TYPE: 'Release Type',
|
RELEASE_TYPE: 'Release Type',
|
||||||
@@ -356,7 +359,13 @@ const en: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Firmware Version Information',
|
FIRMWARE_VERSION_INFO: 'Firmware Version Information',
|
||||||
NO_DATA: 'No data',
|
NO_DATA: 'No data',
|
||||||
USER_PROFILE: 'User Profile',
|
USER_PROFILE: 'User Profile',
|
||||||
STORED_VERSIONS: 'Stored Versions'
|
STORED_VERSIONS: 'Stored Versions',
|
||||||
|
ONLINE_HELP: 'online help',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Important Messages',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'This upgrade requires a factory reset. Make sure you first download a System Backup before continuing, and then upload this file after the new version is installed.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'You are upgrading to a new major version. Make sure you have read the ChangeLog for any breaking changes.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'This will create a backup of your full system configuration and settings. All passwords will be readable in the backup file. Be careful with sharing! Do you want to continue?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const fr: Translation = {
|
|||||||
BUFFER_SIZE: 'Max taille du buffer',
|
BUFFER_SIZE: 'Max taille du buffer',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
|
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les données',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système',
|
||||||
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
|
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||||
ERROR: 'Erreur inattendue, veuillez réessayer',
|
ERROR: 'Erreur inattendue, veuillez réessayer',
|
||||||
@@ -219,6 +220,7 @@ const fr: Translation = {
|
|||||||
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: 'Type de découverte',
|
MQTT_PUBLISH_TEXT_5: 'Type de découverte',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Format des nombres',
|
||||||
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',
|
||||||
@@ -348,6 +350,7 @@ const fr: Translation = {
|
|||||||
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
|
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
|
||||||
NO_DATA_2: 'module pour les marquer.',
|
NO_DATA_2: 'module pour les marquer.',
|
||||||
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
|
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
|
||||||
|
NO_GPIO: "Aucun GPIO disponible n'a été détecté",
|
||||||
THIS_VERSION: 'Cette version',
|
THIS_VERSION: 'Cette version',
|
||||||
PLATFORM: 'Plateforme',
|
PLATFORM: 'Plateforme',
|
||||||
RELEASE_TYPE: 'Type de version',
|
RELEASE_TYPE: 'Type de version',
|
||||||
@@ -356,7 +359,13 @@ const fr: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
|
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
|
||||||
NO_DATA: 'Aucune donnée',
|
NO_DATA: 'Aucune donnée',
|
||||||
USER_PROFILE: 'Profil utilisateur',
|
USER_PROFILE: 'Profil utilisateur',
|
||||||
STORED_VERSIONS: 'Versions stockées'
|
STORED_VERSIONS: 'Versions stockées',
|
||||||
|
ONLINE_HELP: 'aide en ligne',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Mettre à jour les messages importants',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Cette mise à jour nécessite une réinitialisation de fabrique. Assurez-vous de télécharger une sauvegarde système avant de continuer, et de la charger après l\'installation de la nouvelle version.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Vous mettez à jour vers une nouvelle version majeure. Assurez-vous de lire le ChangeLog pour tout changement important.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Cela créera une sauvegarde de votre configuration et paramètres complets. Tous les mots de passe seront lisibles dans le fichier de sauvegarde. Soyez prudent avec le partage ! Voulez-vous continuer ?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const it: Translation = {
|
|||||||
BUFFER_SIZE: 'Max Buffer Size',
|
BUFFER_SIZE: 'Max Buffer Size',
|
||||||
COMPACT: 'Compatto',
|
COMPACT: 'Compatto',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i dati',
|
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema',
|
||||||
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
|
||||||
ERROR: 'Errore Inaspettato, prego tenta ancora',
|
ERROR: 'Errore Inaspettato, prego tenta ancora',
|
||||||
@@ -219,6 +220,7 @@ const it: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Abilita rilevamento MQTT (Home Assistant, Domoticz)',
|
MQTT_PUBLISH_TEXT_3: 'Abilita rilevamento MQTT (Home Assistant, Domoticz)',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefisso per gli argomenti di scoperta',
|
MQTT_PUBLISH_TEXT_4: 'Prefisso per gli argomenti di scoperta',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Formato numero di input',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Pubblica intervalli',
|
MQTT_PUBLISH_INTERVALS: 'Pubblica intervalli',
|
||||||
MQTT_INT_BOILER: 'Caldaie e Pompe di Calore',
|
MQTT_INT_BOILER: 'Caldaie e Pompe di Calore',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostati',
|
MQTT_INT_THERMOSTATS: 'Termostati',
|
||||||
@@ -348,6 +350,7 @@ const it: Translation = {
|
|||||||
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
|
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
|
||||||
NO_DATA_2: 'modulo per marcarle.',
|
NO_DATA_2: 'modulo per marcarle.',
|
||||||
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
|
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
|
||||||
|
NO_GPIO: 'Non è stato trovato alcun GPIO disponibile',
|
||||||
THIS_VERSION: 'Questa versione',
|
THIS_VERSION: 'Questa versione',
|
||||||
PLATFORM: 'Piattaforma',
|
PLATFORM: 'Piattaforma',
|
||||||
RELEASE_TYPE: 'Tipo di rilascio',
|
RELEASE_TYPE: 'Tipo di rilascio',
|
||||||
@@ -356,7 +359,13 @@ const it: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
|
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
|
||||||
NO_DATA: 'Nessun dato',
|
NO_DATA: 'Nessun dato',
|
||||||
USER_PROFILE: 'Profilo utente',
|
USER_PROFILE: 'Profilo utente',
|
||||||
STORED_VERSIONS: 'Versioni memorizzate'
|
STORED_VERSIONS: 'Versioni memorizzate',
|
||||||
|
ONLINE_HELP: 'aiuto online',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Aggiorna Messaggi Importanti',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Questa aggiornamento richiede un ripristino di fabbrica. Assicurati di prima scaricare un backup del sistema prima di continuare, e poi caricare questo file dopo l\'installazione della nuova versione.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Stai aggiornando a una nuova versione principale. Assicurati di aver letto il ChangeLog per qualsiasi cambiamento importante.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Questo creerà un backup delle tue configurazioni e impostazioni complete. Tutte le password saranno leggibili nel file di backup. Sei sicuro di voler continuare?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const nl: Translation = {
|
|||||||
REFRESH: 'Ververs',
|
REFRESH: 'Ververs',
|
||||||
EXPORT: 'Export',
|
EXPORT: 'Export',
|
||||||
FAVORITES: "Favorieten",
|
FAVORITES: "Favorieten",
|
||||||
DEVICE_DETAILS: 'Device Gegevens',
|
DEVICE_DETAILS: 'Apparaat Gegevens',
|
||||||
ID_OF: '{0} ID',
|
ID_OF: '{0} ID',
|
||||||
DEVICE: 'Apparaat',
|
DEVICE: 'Apparaat',
|
||||||
PRODUCT: 'Product',
|
PRODUCT: 'Product',
|
||||||
@@ -65,7 +65,7 @@ const nl: Translation = {
|
|||||||
TEMP_SENSOR: 'Temperatuur sensor',
|
TEMP_SENSOR: 'Temperatuur sensor',
|
||||||
TEMP_SENSORS: 'Temperatuur Sensoren',
|
TEMP_SENSORS: 'Temperatuur Sensoren',
|
||||||
WRITE_CMD_SENT: 'Schrijf commando gestuurd',
|
WRITE_CMD_SENT: 'Schrijf commando gestuurd',
|
||||||
EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden dan loop de instellingen na en in het bijzonder het apparaat type profiel na.',
|
EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden loop dan de instellingen na en in het bijzonder het apparaat type profiel.',
|
||||||
EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...',
|
EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...',
|
||||||
CONNECTED: 'Verbonden',
|
CONNECTED: 'Verbonden',
|
||||||
TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus',
|
TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus',
|
||||||
@@ -75,7 +75,7 @@ const nl: Translation = {
|
|||||||
EMS_DEVICE: 'EMS Apparaat',
|
EMS_DEVICE: 'EMS Apparaat',
|
||||||
SUCCESS: 'SUCCESS',
|
SUCCESS: 'SUCCESS',
|
||||||
FAIL: 'MISLUKT',
|
FAIL: 'MISLUKT',
|
||||||
QUALITY: 'QUALITEIT',
|
QUALITY: 'KWALITEIT',
|
||||||
SCAN: 'Scan',
|
SCAN: 'Scan',
|
||||||
STATUS_NAMES: [
|
STATUS_NAMES: [
|
||||||
'EMS Telegrammen ontvangen (Rx)',
|
'EMS Telegrammen ontvangen (Rx)',
|
||||||
@@ -120,7 +120,7 @@ const nl: Translation = {
|
|||||||
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
||||||
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
||||||
TRIGGER_TIME: 'Trigger tijd',
|
TRIGGER_TIME: 'Trigger tijd',
|
||||||
COLD_SHOT_DURATION: 'Tijd Shot koud water',
|
COLD_SHOT_DURATION: 'Lengte koud water puls',
|
||||||
FORMATTING_OPTIONS: 'Formatteringsopties',
|
FORMATTING_OPTIONS: 'Formatteringsopties',
|
||||||
BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat web',
|
BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat web',
|
||||||
BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT',
|
BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT',
|
||||||
@@ -143,7 +143,7 @@ const nl: Translation = {
|
|||||||
CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub',
|
CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub',
|
||||||
CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen',
|
CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen',
|
||||||
CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties',
|
CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties',
|
||||||
CUSTOMIZATIONS_HELP_2: 'Markeer as favoriet',
|
CUSTOMIZATIONS_HELP_2: 'Markeer als favoriet',
|
||||||
CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit',
|
CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit',
|
||||||
CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API',
|
CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API',
|
||||||
CUSTOMIZATIONS_HELP_5: 'verbergen voor apparaten',
|
CUSTOMIZATIONS_HELP_5: 'verbergen voor apparaten',
|
||||||
@@ -186,12 +186,13 @@ const nl: Translation = {
|
|||||||
BUFFER_SIZE: 'Max buffer grootte',
|
BUFFER_SIZE: 'Max buffer grootte',
|
||||||
COMPACT: 'Compact',
|
COMPACT: 'Compact',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen',
|
DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle data',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup',
|
||||||
UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)',
|
UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
|
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
|
||||||
ERROR: 'Onverwachte fout, probeer opnieuw',
|
ERROR: 'Onverwachte fout, probeer opnieuw',
|
||||||
TIME_SET: 'Tijd ingesteld',
|
TIME_SET: 'Tijd ingesteld',
|
||||||
MANAGE_USERS: 'Beheer Gebruikers',
|
MANAGE_USERS: 'Gebruikersbeheer',
|
||||||
IS_ADMIN: 'is Admin',
|
IS_ADMIN: 'is Admin',
|
||||||
USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren',
|
USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren',
|
||||||
ADD: 'Toevoegen',
|
ADD: 'Toevoegen',
|
||||||
@@ -200,7 +201,7 @@ const nl: Translation = {
|
|||||||
GENERATING_TOKEN: 'Token aan het genereren',
|
GENERATING_TOKEN: 'Token aan het genereren',
|
||||||
USER: 'Gebruiker',
|
USER: 'Gebruiker',
|
||||||
MODIFY: 'Aanpassen',
|
MODIFY: 'Aanpassen',
|
||||||
SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te signeren en ook om admin privileges te activeren in de console.',
|
SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te ondertekenen en ook om admin privileges te activeren in de console.',
|
||||||
NOT_ENABLED: 'Niet geactiveerd',
|
NOT_ENABLED: 'Niet geactiveerd',
|
||||||
ERRORS_OF: '{0} Foutmeldingen',
|
ERRORS_OF: '{0} Foutmeldingen',
|
||||||
DISCONNECT_REASON: 'Verbinding verbroken vanwege',
|
DISCONNECT_REASON: 'Verbinding verbroken vanwege',
|
||||||
@@ -219,6 +220,7 @@ const nl: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Activeer MQTT Discovery',
|
MQTT_PUBLISH_TEXT_3: 'Activeer MQTT Discovery',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix voor de Discovery topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefix voor de Discovery topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Getalformaat',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Publicatie intervallen',
|
MQTT_PUBLISH_INTERVALS: 'Publicatie intervallen',
|
||||||
MQTT_INT_BOILER: 'CV ketels en warmtepompen',
|
MQTT_INT_BOILER: 'CV ketels en warmtepompen',
|
||||||
MQTT_INT_THERMOSTATS: 'Thermostaten',
|
MQTT_INT_THERMOSTATS: 'Thermostaten',
|
||||||
@@ -348,6 +350,7 @@ const nl: Translation = {
|
|||||||
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.',
|
||||||
NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar',
|
NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar',
|
||||||
|
NO_GPIO: 'Er is geen beschikbare GPIO gevonden',
|
||||||
THIS_VERSION: 'Deze Versie',
|
THIS_VERSION: 'Deze Versie',
|
||||||
PLATFORM: 'Platform',
|
PLATFORM: 'Platform',
|
||||||
RELEASE_TYPE: 'Release Typ',
|
RELEASE_TYPE: 'Release Typ',
|
||||||
@@ -356,7 +359,13 @@ const nl: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
|
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
|
||||||
NO_DATA: 'Geen data',
|
NO_DATA: 'Geen data',
|
||||||
USER_PROFILE: 'Gebruikersprofiel',
|
USER_PROFILE: 'Gebruikersprofiel',
|
||||||
STORED_VERSIONS: 'Opgeslagen versies'
|
STORED_VERSIONS: 'Opgeslagen versies',
|
||||||
|
ONLINE_HELP: 'online help',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Belangrijke Berichten',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Deze upgrade vereist een fabrieksinstelling. Zorg ervoor dat u eerst een Systeem Backup download voordat u doorgaat, en upload deze file na de installatie van de nieuwe versie.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'U updatet naar een nieuwe grote versie. Zorg ervoor dat u de ChangeLog hebt gelezen voor alle brekende wijzigingen.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Dit zal een back-up van uw volledige systeemconfiguratie en instellingen maken. Alle wachtwoorden zijn leesbaar in het back-upbestand. Wees voorzichtig bij delen! Wilt u doorgaan?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
@@ -186,7 +186,8 @@ const no: Translation = {
|
|||||||
BUFFER_SIZE: 'Max Buffer Størrelse',
|
BUFFER_SIZE: 'Max Buffer Størrelse',
|
||||||
COMPACT: 'Komprimere',
|
COMPACT: 'Komprimere',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
|
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle data',
|
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi',
|
||||||
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
|
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
|
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
|
||||||
ERROR: 'Ukjent feil, prøv igjen',
|
ERROR: 'Ukjent feil, prøv igjen',
|
||||||
@@ -219,6 +220,7 @@ const no: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Aktiver MQTT Discovery',
|
MQTT_PUBLISH_TEXT_3: 'Aktiver MQTT Discovery',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefiks for Discovery topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefiks for Discovery topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
MQTT_PUBLISH_TEXT_5: 'Discovery type',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Nummerformat',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Publiseringsintervall',
|
MQTT_PUBLISH_INTERVALS: 'Publiseringsintervall',
|
||||||
MQTT_INT_BOILER: 'Fyr/Varmepumpe',
|
MQTT_INT_BOILER: 'Fyr/Varmepumpe',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostat',
|
MQTT_INT_THERMOSTATS: 'Termostat',
|
||||||
@@ -348,6 +350,7 @@ const no: Translation = {
|
|||||||
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
|
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
|
||||||
NO_DATA_2: 'modul for å markere dem.',
|
NO_DATA_2: 'modul for å markere dem.',
|
||||||
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
|
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
|
||||||
|
NO_GPIO: 'Det ble ikke funnet noen tilgjengelige GPIO-porter',
|
||||||
THIS_VERSION: 'Denne versjonen',
|
THIS_VERSION: 'Denne versjonen',
|
||||||
PLATFORM: 'Plattform',
|
PLATFORM: 'Plattform',
|
||||||
RELEASE_TYPE: 'Utgivelses type',
|
RELEASE_TYPE: 'Utgivelses type',
|
||||||
@@ -356,7 +359,13 @@ const no: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
|
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
|
||||||
NO_DATA: 'Ingen data',
|
NO_DATA: 'Ingen data',
|
||||||
USER_PROFILE: 'Brukerprofil',
|
USER_PROFILE: 'Brukerprofil',
|
||||||
STORED_VERSIONS: 'Lagret versjoner'
|
STORED_VERSIONS: 'Lagret versjoner',
|
||||||
|
ONLINE_HELP: 'online hjelp',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Oppdater viktige meldinger',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Denne oppdateringen krever en fabriksinstilling. Sørg for at du først lastet ned en System Backup før du fortsetter, og last denne filen etter at den nye versjonen er installert.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Du oppdaterer til en ny hovedversjon. Sørg for at du har lest ChangeLog for eventuelle bruddende endringer.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Dette vil lage en sikkerhetskopi av din fullstendige systemkonfigurasjon og innstillinger. Alle passord vil være lesbare i sikkerhetskopien. Vær forsiktig med deling! Vil du fortsette?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const pl: BaseTranslation = {
|
|||||||
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',
|
||||||
COMPACT: 'Kompaktowy',
|
COMPACT: 'Kompaktowy',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
|
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie dane',
|
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu',
|
||||||
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
|
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
|
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
|
||||||
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
|
||||||
@@ -219,6 +220,7 @@ const pl: BaseTranslation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Włącz opcję "MQTT discovery"',
|
MQTT_PUBLISH_TEXT_3: 'Włącz opcję "MQTT discovery"',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefiks dla "MQTT discovery"',
|
MQTT_PUBLISH_TEXT_4: 'Prefiks dla "MQTT discovery"',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Typ "MQTT discovery"',
|
MQTT_PUBLISH_TEXT_5: 'Typ "MQTT discovery"',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Format liczby',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Interwały publikowania',
|
MQTT_PUBLISH_INTERVALS: 'Interwały publikowania',
|
||||||
MQTT_INT_BOILER: 'Kotły i pompy ciepła',
|
MQTT_INT_BOILER: 'Kotły i pompy ciepła',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||||
@@ -348,6 +350,7 @@ const pl: BaseTranslation = {
|
|||||||
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
|
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
|
||||||
NO_DATA_2: 'moduł do ich oznaczenia.',
|
NO_DATA_2: 'moduł do ich oznaczenia.',
|
||||||
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
|
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
|
||||||
|
NO_GPIO: 'Nie znaleziono dostępnych pinów GPIO',
|
||||||
THIS_VERSION: 'Ta wersja',
|
THIS_VERSION: 'Ta wersja',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Typ wydania',
|
RELEASE_TYPE: 'Typ wydania',
|
||||||
@@ -356,7 +359,13 @@ const pl: BaseTranslation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
|
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
|
||||||
NO_DATA: 'Brak danych',
|
NO_DATA: 'Brak danych',
|
||||||
USER_PROFILE: 'Profil użytkownika',
|
USER_PROFILE: 'Profil użytkownika',
|
||||||
STORED_VERSIONS: 'Zapisane wersje'
|
STORED_VERSIONS: 'Zapisane wersje',
|
||||||
|
ONLINE_HELP: 'pomoc online',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizuj ważne wiadomości',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Ta aktualizacja wymaga resetu fabrycznego. Upewnij się, że najpierw pobierzesz kopię zapasową systemu przed kontynuowaniem, a następnie przesuń tę plik po zainstalowaniu nowej wersji.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujesz się do nowej głównej wersji. Upewnij się, że przeczytałeś ChangeLog dla wszelkich istotnych zmian.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'To spowoduje utworzenie kopii zapasowej całej konfiguracji i ustawień systemu. Wszystkie hasła będą widoczne w pliku kopii zapasowej. Bądź ostrożny przy udostępnianiu! Chcesz kontynuować?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const sk: Translation = {
|
|||||||
LANGUAGE: 'Jazyk',
|
LANGUAGE: 'Jazyk',
|
||||||
RETRY: 'Opakovať',
|
RETRY: 'Opakovať',
|
||||||
LOADING: 'Načítanie',
|
LOADING: 'Načítanie',
|
||||||
IS_REQUIRED: '{0} je požadovaných',
|
IS_REQUIRED: '{0} je požadovaná',
|
||||||
SIGN_IN: 'Prihlásiť sa',
|
SIGN_IN: 'Prihlásiť sa',
|
||||||
SIGN_OUT: 'Odhlásiť sa',
|
SIGN_OUT: 'Odhlásiť sa',
|
||||||
USERNAME: 'Užívateľské meno',
|
USERNAME: 'Užívateľské meno',
|
||||||
@@ -186,7 +186,8 @@ const sk: Translation = {
|
|||||||
BUFFER_SIZE: 'Buffer-max. veľkosť',
|
BUFFER_SIZE: 'Buffer-max. veľkosť',
|
||||||
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í',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky dáta',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
|
||||||
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
|
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem',
|
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',
|
||||||
@@ -219,6 +220,7 @@ const sk: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Povolenie zisťovania MQTT',
|
MQTT_PUBLISH_TEXT_3: 'Povolenie zisťovania MQTT',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Predpona tém Discovery',
|
MQTT_PUBLISH_TEXT_4: 'Predpona tém Discovery',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Typ zistenia',
|
MQTT_PUBLISH_TEXT_5: 'Typ zistenia',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Formát čísla',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Intervaly zverejňovania',
|
MQTT_PUBLISH_INTERVALS: 'Intervaly zverejňovania',
|
||||||
MQTT_INT_BOILER: 'Kotly a tepelné čerpadlá',
|
MQTT_INT_BOILER: 'Kotly a tepelné čerpadlá',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||||
@@ -274,11 +276,11 @@ const sk: Translation = {
|
|||||||
NETWORK_SUBNET: 'Maska podsiete',
|
NETWORK_SUBNET: 'Maska podsiete',
|
||||||
NETWORK_DNS: 'DNS servery',
|
NETWORK_DNS: 'DNS servery',
|
||||||
ADDRESS_OF: '{0} adresa',
|
ADDRESS_OF: '{0} adresa',
|
||||||
ADMINISTRATOR: 'Administrator',
|
ADMINISTRATOR: 'Administrátor',
|
||||||
GUEST: 'Hosť',
|
GUEST: 'Hosť',
|
||||||
NEW: 'Nová',
|
NEW: 'Novú',
|
||||||
NEW_NAME_OF: 'Nový názov {0}',
|
NEW_NAME_OF: 'Nový názov {0}',
|
||||||
ENTITY: 'entita',
|
ENTITY: 'entitu',
|
||||||
MIN: 'min',
|
MIN: 'min',
|
||||||
MAX: 'max',
|
MAX: 'max',
|
||||||
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
|
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
|
||||||
@@ -348,6 +350,7 @@ const sk: Translation = {
|
|||||||
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.',
|
||||||
NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na',
|
NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na',
|
||||||
|
NO_GPIO: 'Nebol nájdený žiadny dostupný GPIO',
|
||||||
THIS_VERSION: 'Táto verzia',
|
THIS_VERSION: 'Táto verzia',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Typ vydania',
|
RELEASE_TYPE: 'Typ vydania',
|
||||||
@@ -356,7 +359,13 @@ const sk: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
|
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
|
||||||
NO_DATA: 'Žiadne dáta',
|
NO_DATA: 'Žiadne dáta',
|
||||||
USER_PROFILE: 'Profil používateľa',
|
USER_PROFILE: 'Profil používateľa',
|
||||||
STORED_VERSIONS: 'Uložené verzie'
|
STORED_VERSIONS: 'Uložené verzie',
|
||||||
|
ONLINE_HELP: 'online pomoc',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovať dôležité správy',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Táto aktualizácia vyžaduje reštart základných nastavení. Uistite sa, že najprv stiahnete systémovú zálohu pred pokračovaním, a potom nahrajte tento súbor po instalácii novej verzie.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete sa na novú hlavnú verziu. Uistite sa, že ste prečítali ChangeLog pre akékoľvek dôležité zmeny.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Toto vytvorí zálohu všetkých vašich celých systémových konfigurácií a nastavení. Všetky hesla budú čitateľné v zálohovom súbore. Buďte opatrní pri zdieľaní! Chcete pokračovať?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sk;
|
export default sk;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const sv: Translation = {
|
|||||||
BUFFER_SIZE: 'Max bufferstorlek',
|
BUFFER_SIZE: 'Max bufferstorlek',
|
||||||
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',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla data',
|
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia',
|
||||||
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
|
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
|
||||||
UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här',
|
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',
|
||||||
@@ -219,6 +220,7 @@ const sv: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'Aktivera MQTT Discovery',
|
MQTT_PUBLISH_TEXT_3: 'Aktivera MQTT Discovery',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix för Discovery topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefix för Discovery topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discoverytyp',
|
MQTT_PUBLISH_TEXT_5: 'Discoverytyp',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Nummerformat',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Publiceringsintervall',
|
MQTT_PUBLISH_INTERVALS: 'Publiceringsintervall',
|
||||||
MQTT_INT_BOILER: 'Värmepump/panna',
|
MQTT_INT_BOILER: 'Värmepump/panna',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostater',
|
MQTT_INT_THERMOSTATS: 'Termostater',
|
||||||
@@ -348,6 +350,7 @@ const sv: Translation = {
|
|||||||
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
|
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
|
||||||
NO_DATA_2: 'modul för att markera dem.',
|
NO_DATA_2: 'modul för att markera dem.',
|
||||||
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
|
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
|
||||||
|
NO_GPIO: 'Inga tillgängliga GPIO-portar hittades',
|
||||||
THIS_VERSION: 'Denna version',
|
THIS_VERSION: 'Denna version',
|
||||||
PLATFORM: 'Plattform',
|
PLATFORM: 'Plattform',
|
||||||
RELEASE_TYPE: 'Utgivelsestyp',
|
RELEASE_TYPE: 'Utgivelsestyp',
|
||||||
@@ -356,7 +359,13 @@ const sv: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
|
FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
|
||||||
NO_DATA: 'Ingen data',
|
NO_DATA: 'Ingen data',
|
||||||
USER_PROFILE: 'Användarprofil',
|
USER_PROFILE: 'Användarprofil',
|
||||||
STORED_VERSIONS: 'Lagrad versioner'
|
STORED_VERSIONS: 'Lagrad versioner',
|
||||||
|
ONLINE_HELP: 'online hjälp',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Uppdatera viktiga meddelanden',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Denna uppdatering kräver en fabriksåterställning. Se till att du först laddar ned en System Backup innan du fortsätter, och ladda upp denna fil efter att den nya versionen är installerad.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Du uppdaterar till en ny huvudversion. Se till att du har läst ChangeLog för eventuella brkande ändringar.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Detta kommer att skapa en säkerhetskopia av din fullständiga systemkonfiguration och inställningar. Alla lösenord kommer att vara läsbara i säkerhetskopien. Var försiktig med att dela! Vill du fortsätta?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ const tr: Translation = {
|
|||||||
BUFFER_SIZE: 'En fazla bellek boyutu',
|
BUFFER_SIZE: 'En fazla bellek boyutu',
|
||||||
COMPACT: 'Sıkışık',
|
COMPACT: 'Sıkışık',
|
||||||
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
|
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
|
||||||
DOWNLOAD_SETTINGS_TEXT2: 'Tüm verileri dışarı al',
|
DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al',
|
||||||
|
DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme',
|
||||||
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
|
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
|
||||||
UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
|
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.',
|
||||||
@@ -219,6 +220,7 @@ const tr: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_3: 'MQTT keşfi etkinleştir (Home Assistant, Domoticz)',
|
MQTT_PUBLISH_TEXT_3: 'MQTT keşfi etkinleştir (Home Assistant, Domoticz)',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Keşif konuları için ön ek',
|
MQTT_PUBLISH_TEXT_4: 'Keşif konuları için ön ek',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Domoticz Format',
|
MQTT_PUBLISH_TEXT_5: 'Domoticz Format',
|
||||||
|
MQTT_INPUT_NUMBER_FORMAT: 'Sayı Biçimi',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Yayınlama aralıkları',
|
MQTT_PUBLISH_INTERVALS: 'Yayınlama aralıkları',
|
||||||
MQTT_INT_BOILER: 'Kazanlar ve Isı Pompaları',
|
MQTT_INT_BOILER: 'Kazanlar ve Isı Pompaları',
|
||||||
MQTT_INT_THERMOSTATS: 'Termostatlar',
|
MQTT_INT_THERMOSTATS: 'Termostatlar',
|
||||||
@@ -348,6 +350,7 @@ const tr: Translation = {
|
|||||||
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
|
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
|
||||||
NO_DATA_2: 'modülünü kullanın.',
|
NO_DATA_2: 'modülünü kullanın.',
|
||||||
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
|
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
|
||||||
|
NO_GPIO: 'Kullanılabilir GPIO bulunamadı',
|
||||||
THIS_VERSION: 'Bu Sürüm',
|
THIS_VERSION: 'Bu Sürüm',
|
||||||
PLATFORM: 'Platforma',
|
PLATFORM: 'Platforma',
|
||||||
RELEASE_TYPE: 'Sürüm Tipi',
|
RELEASE_TYPE: 'Sürüm Tipi',
|
||||||
@@ -356,7 +359,13 @@ const tr: Translation = {
|
|||||||
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
|
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
|
||||||
NO_DATA: 'Hiçbir veri yok',
|
NO_DATA: 'Hiçbir veri yok',
|
||||||
USER_PROFILE: 'Kullanıcı Profili',
|
USER_PROFILE: 'Kullanıcı Profili',
|
||||||
STORED_VERSIONS: 'Kaydedilmiş Sürümler'
|
STORED_VERSIONS: 'Kaydedilmiş Sürümler',
|
||||||
|
ONLINE_HELP: 'online yardım',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES: 'Önemli Mesajları Güncelle',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_1: 'Bu güncelleme továrnı ayarlarını gerektirir. Yapılandırmanızı ve ayarlarınızı önce yedekleyin ve ardından yeni sürüm yüklendikten sonra yükleyin.',
|
||||||
|
UPGRADE_IMPORTANT_MESSAGES_2: 'Yeni bir büyük sürüme yükselteceksiniz. Değişiklikleri ChangeLogı okuduğunuzdan emin olun.',
|
||||||
|
WARNING_SYSTEM_BACKUP: 'Bu, sistem yapılandırmanızı ve ayarlarınızın bir yedeklemesi oluşturacaktır. Tüm şifreler yedekleme dosyasında okunabilir olacaktır. Paylaşırken dikkatli olun! Devam etmek istediğinize emin misiniz?'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tr;
|
export default tr;
|
||||||
|
|||||||
@@ -49,4 +49,5 @@ export interface MqttSettingsType {
|
|||||||
publish_single2cmd: boolean;
|
publish_single2cmd: boolean;
|
||||||
discovery_prefix: string;
|
discovery_prefix: string;
|
||||||
discovery_type: number;
|
discovery_type: number;
|
||||||
|
ha_number_mode: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export interface SystemStatus {
|
|||||||
free_psram?: number;
|
free_psram?: number;
|
||||||
free_caps: number;
|
free_caps: number;
|
||||||
model: string;
|
model: string;
|
||||||
|
board: string;
|
||||||
has_loader: boolean;
|
has_loader: boolean;
|
||||||
has_partition: boolean;
|
has_partition: boolean;
|
||||||
partitions: {
|
partitions: {
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export const saveFile = (
|
|||||||
}, 100);
|
}, 100);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to save file:', error);
|
console.error('Failed to save file:', error);
|
||||||
throw new Error(`Unable to save file: ${filename}${extension}`);
|
throw new Error(`Unable to save file: ${filename}${extension}`, {
|
||||||
|
cause: error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
const DEFAULT_DELAY = 3000;
|
const DEFAULT_DELAY = 5000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook for setting up an interval with proper cleanup
|
* Custom hook for setting up an interval with proper cleanup
|
||||||
|
|||||||
@@ -1,6 +1,20 @@
|
|||||||
import type { InternalRuleItem, ValidateOption } from 'async-validator';
|
import type {
|
||||||
|
InternalRuleItem,
|
||||||
|
ValidateFieldsError,
|
||||||
|
ValidateOption
|
||||||
|
} from 'async-validator';
|
||||||
import type Schema from 'async-validator';
|
import type Schema from 'async-validator';
|
||||||
|
|
||||||
|
export class ValidationError extends Error {
|
||||||
|
readonly fieldErrors: ValidateFieldsError;
|
||||||
|
|
||||||
|
constructor(fieldErrors: ValidateFieldsError) {
|
||||||
|
super('Validation failed');
|
||||||
|
this.name = 'ValidationError';
|
||||||
|
this.fieldErrors = fieldErrors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const validate = <T extends object>(
|
export const validate = <T extends object>(
|
||||||
validator: Schema,
|
validator: Schema,
|
||||||
source: Partial<T>,
|
source: Partial<T>,
|
||||||
@@ -8,7 +22,7 @@ export const validate = <T extends object>(
|
|||||||
): Promise<T> =>
|
): Promise<T> =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
void validator.validate(source, options ?? {}, (errors, fieldErrors) => {
|
void validator.validate(source, options ?? {}, (errors, fieldErrors) => {
|
||||||
errors ? reject(fieldErrors as Error) : resolve(source as T);
|
errors ? reject(new ValidationError(fieldErrors)) : resolve(source as T);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import preact from '@preact/preset-vite';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { Plugin, defineConfig } from 'vite';
|
import { Plugin, PluginOption, defineConfig } from 'vite';
|
||||||
import viteImagemin from 'vite-plugin-imagemin';
|
import viteImagemin from 'vite-plugin-imagemin';
|
||||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
|
||||||
import zlib from 'zlib';
|
import zlib from 'zlib';
|
||||||
|
|
||||||
// @ts-expect-error - mock server doesn't have type declarations
|
// @ts-expect-error - mock server doesn't have type declarations
|
||||||
@@ -16,7 +15,7 @@ const REPEAT_CHAR = '=';
|
|||||||
const REPEAT_COUNT = 50;
|
const REPEAT_COUNT = 50;
|
||||||
const DEFAULT_OUT_DIR = 'dist';
|
const DEFAULT_OUT_DIR = 'dist';
|
||||||
const ES_TARGET = 'es2020';
|
const ES_TARGET = 'es2020';
|
||||||
const CHUNK_SIZE_WARNING_LIMIT = 512;
|
const CHUNK_SIZE_WARNING_LIMIT = 1024;
|
||||||
const ASSETS_INLINE_LIMIT = 4096;
|
const ASSETS_INLINE_LIMIT = 4096;
|
||||||
|
|
||||||
// Common resolve aliases
|
// Common resolve aliases
|
||||||
@@ -99,16 +98,31 @@ const createPreactPlugin = (devToolsEnabled: boolean) =>
|
|||||||
prefreshEnabled: false
|
prefreshEnabled: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Patch preact/compat to export stub React 19 APIs (use, useOptimistic) so that
|
||||||
|
// react-router v7 doesn't trigger IMPORT_IS_UNDEFINED warnings from Rolldown.
|
||||||
|
const preactCompatPatchPlugin = (): Plugin => ({
|
||||||
|
name: 'preact-compat-react19-patch',
|
||||||
|
transform(code, id) {
|
||||||
|
if (id.includes('preact') && id.includes('compat.module.js')) {
|
||||||
|
return {
|
||||||
|
code:
|
||||||
|
code +
|
||||||
|
'\nexport var use = undefined;\nexport var useOptimistic = undefined;\n',
|
||||||
|
map: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Common base plugins
|
// Common base plugins
|
||||||
const createBasePlugins = (
|
const createBasePlugins = (
|
||||||
devToolsEnabled: boolean,
|
devToolsEnabled: boolean,
|
||||||
includeBundleReporter = true
|
includeBundleReporter = true
|
||||||
) => {
|
): PluginOption[] => {
|
||||||
const plugins = [
|
const plugins: PluginOption[] = [
|
||||||
createPreactPlugin(devToolsEnabled),
|
createPreactPlugin(devToolsEnabled),
|
||||||
viteTsconfigPaths({
|
preactCompatPatchPlugin()
|
||||||
projects: ['./tsconfig.json']
|
|
||||||
})
|
|
||||||
];
|
];
|
||||||
if (includeBundleReporter) {
|
if (includeBundleReporter) {
|
||||||
plugins.push(bundleSizeReporter());
|
plugins.push(bundleSizeReporter());
|
||||||
@@ -116,33 +130,9 @@ const createBasePlugins = (
|
|||||||
return plugins;
|
return plugins;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Manual chunk splitting strategy
|
const manualChunks = (id: string): string | undefined => {
|
||||||
const createManualChunks = (detailed = false) => {
|
if (id.includes('node_modules')) return 'vendor';
|
||||||
return (id: string): string | undefined => {
|
|
||||||
if (id.includes('node_modules')) {
|
|
||||||
if (id.includes('preact')) return '@preact';
|
|
||||||
if (detailed) {
|
|
||||||
if (id.includes('react-router')) return '@react-router';
|
|
||||||
if (id.includes('@mui/material')) return '@mui-material';
|
|
||||||
if (id.includes('@mui/icons-material')) return '@mui-icons';
|
|
||||||
if (id.includes('alova')) return '@alova';
|
|
||||||
if (id.includes('typesafe-i18n')) return '@i18n';
|
|
||||||
if (id.includes('react-toastify')) return '@toastify';
|
|
||||||
if (id.includes('@table-library')) return '@table-library';
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
if (detailed) {
|
|
||||||
if (id.includes('components/')) return 'components';
|
|
||||||
if (id.includes('app/')) return 'app';
|
|
||||||
if (id.includes('utils/')) return 'utils';
|
|
||||||
if (id.includes('api/')) return 'api';
|
|
||||||
}
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common build base configuration
|
// Common build base configuration
|
||||||
@@ -227,7 +217,8 @@ export default defineConfig(
|
|||||||
plugins: [...createBasePlugins(true, true), mockServer()],
|
plugins: [...createBasePlugins(true, true), mockServer()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: RESOLVE_ALIASES,
|
alias: RESOLVE_ALIASES,
|
||||||
extensions: RESOLVE_EXTENSIONS
|
extensions: RESOLVE_EXTENSIONS,
|
||||||
|
tsconfigPaths: true
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
open: true,
|
open: true,
|
||||||
@@ -256,7 +247,8 @@ export default defineConfig(
|
|||||||
plugins: createBasePlugins(false, true),
|
plugins: createBasePlugins(false, true),
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: RESOLVE_ALIASES,
|
alias: RESOLVE_ALIASES,
|
||||||
extensions: RESOLVE_EXTENSIONS
|
extensions: RESOLVE_EXTENSIONS,
|
||||||
|
tsconfigPaths: true
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
...createBaseBuildConfig(),
|
...createBaseBuildConfig(),
|
||||||
@@ -267,7 +259,7 @@ export default defineConfig(
|
|||||||
moduleSideEffects: false
|
moduleSideEffects: false
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
manualChunks: createManualChunks(false)
|
manualChunks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,7 +282,8 @@ export default defineConfig(
|
|||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: RESOLVE_ALIASES,
|
alias: RESOLVE_ALIASES,
|
||||||
extensions: RESOLVE_EXTENSIONS
|
extensions: RESOLVE_EXTENSIONS,
|
||||||
|
tsconfigPaths: true
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
...createBaseBuildConfig(),
|
...createBaseBuildConfig(),
|
||||||
@@ -299,15 +292,14 @@ export default defineConfig(
|
|||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
treeshake: {
|
treeshake: {
|
||||||
moduleSideEffects: false,
|
moduleSideEffects: false,
|
||||||
propertyReadSideEffects: false,
|
propertyReadSideEffects: false as const,
|
||||||
tryCatchDeoptimization: false,
|
|
||||||
unknownGlobalSideEffects: false
|
unknownGlobalSideEffects: false
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
chunkFileNames: 'assets/[name]-[hash].js',
|
chunkFileNames: 'assets/[name]-[hash].js',
|
||||||
entryFileNames: 'assets/[name]-[hash].js',
|
entryFileNames: 'assets/[name]-[hash].js',
|
||||||
assetFileNames: 'assets/[name]-[hash].[ext]',
|
assetFileNames: 'assets/[name]-[hash].[ext]',
|
||||||
manualChunks: createManualChunks(true),
|
manualChunks,
|
||||||
sourcemap: false
|
sourcemap: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,9 +148,7 @@
|
|||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
#include <driver/rtc_io.h>
|
#include <driver/rtc_io.h>
|
||||||
#include <soc/gpio_struct.h>
|
#include <soc/gpio_struct.h>
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
#include "soc/gpio_periph.h"
|
#include "soc/gpio_periph.h"
|
||||||
#endif // ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
#define PIN_TO_BASEREG(pin) (0)
|
#define PIN_TO_BASEREG(pin) (0)
|
||||||
#define PIN_TO_BITMASK(pin) (pin)
|
#define PIN_TO_BITMASK(pin) (pin)
|
||||||
#define IO_REG_TYPE uint32_t
|
#define IO_REG_TYPE uint32_t
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ ModbusClientTCPasync::~ModbusClientTCPasync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// force close client
|
// force close client
|
||||||
MTA_client.close(true);
|
MTA_client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// optionally manually connect to modbus server. Otherwise connection will be made upon first request
|
// optionally manually connect to modbus server. Otherwise connection will be made upon first request
|
||||||
@@ -79,7 +79,7 @@ void ModbusClientTCPasync::connect(IPAddress host, uint16_t port) {
|
|||||||
// manually disconnect from modbus server. Connection will also auto close after idle time
|
// manually disconnect from modbus server. Connection will also auto close after idle time
|
||||||
void ModbusClientTCPasync::disconnect(bool force) {
|
void ModbusClientTCPasync::disconnect(bool force) {
|
||||||
LOG_D("disconnecting\n");
|
LOG_D("disconnecting\n");
|
||||||
MTA_client.close(force);
|
MTA_client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set timeout value
|
// Set timeout value
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ void ModbusServerTCPasync::onClientConnect(AsyncClient* client) {
|
|||||||
LOG_D("nr clients: %u\n", clients.size());
|
LOG_D("nr clients: %u\n", clients.size());
|
||||||
} else {
|
} else {
|
||||||
LOG_D("max number of clients reached, closing new\n");
|
LOG_D("max number of clients reached, closing new\n");
|
||||||
client->close(true);
|
client->close();
|
||||||
delete client;
|
delete client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
// Include all library components
|
// Include all library components
|
||||||
#include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector
|
#include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector
|
||||||
#include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector
|
#include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector
|
||||||
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector (ESP32 only)
|
||||||
|
#endif
|
||||||
// #include "esp32-psram/InMemoryFile.h" // File interface using vectors
|
// #include "esp32-psram/InMemoryFile.h" // File interface using vectors
|
||||||
// #include "esp32-psram/PSRAM.h" // PSRAM file system
|
// #include "esp32-psram/PSRAM.h" // PSRAM file system
|
||||||
// #include "esp32-psram/HIMEM.h" // HIMEM file system
|
// #include "esp32-psram/HIMEM.h" // HIMEM file system
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// HIMEM is only available on original ESP32
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -360,3 +363,5 @@ class HimemBlock {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esp32_psram
|
} // namespace esp32_psram
|
||||||
|
|
||||||
|
#endif // CONFIG_IDF_TARGET_ESP32
|
||||||
|
|||||||
@@ -238,7 +238,9 @@ using RingBufferStreamPSRAM = RingBufferStream<VectorPSRAM<uint8_t>>;
|
|||||||
/**
|
/**
|
||||||
* @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage
|
* @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage
|
||||||
*/
|
*/
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>;
|
using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type alias for a RingBufferStream that uses std::vector storage
|
* @brief Type alias for a RingBufferStream that uses std::vector storage
|
||||||
|
|||||||
@@ -209,8 +209,10 @@ using TypedRingBufferRAM = TypedRingBuffer<T, std::vector<T>>;
|
|||||||
/**
|
/**
|
||||||
* @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage
|
* @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage
|
||||||
*/
|
*/
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>;
|
using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage
|
* @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user