Compare commits
987 Commits
dev
...
integratio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c62d4a923 | ||
|
|
6e42d009fb | ||
|
|
7d7769ea5d | ||
|
|
3908677fe2 | ||
|
|
9799a2b636 | ||
|
|
099474053e | ||
|
|
efafabed97 | ||
|
|
d463dd0f57 | ||
|
|
c33c14a46f | ||
|
|
2d0c109dc1 | ||
|
|
825d0bed88 | ||
|
|
cd1390916c | ||
|
|
149bdaf146 | ||
|
|
ad628c9cba | ||
|
|
b88f87799e | ||
|
|
1ff7cf1125 | ||
|
|
31db6e51eb | ||
|
|
681d9236f9 | ||
|
|
8aa8af735d | ||
|
|
943d0f103d | ||
|
|
8b195d7f63 | ||
|
|
649ad47e62 | ||
|
|
93dc5765bb | ||
|
|
b000b1b70c | ||
|
|
8707b6e01a | ||
|
|
34abd67f3e | ||
|
|
45f1db9233 | ||
|
|
beb4d1511a | ||
|
|
adeceee71f | ||
|
|
7d4b11d112 | ||
|
|
6733cd4ed1 | ||
|
|
07f361a404 | ||
|
|
ae981ea7f2 | ||
|
|
b7d0f5e36b | ||
|
|
3cbce4df42 | ||
|
|
7e77e40bda | ||
|
|
305805256d | ||
|
|
e36c669dc0 | ||
|
|
71aff9bc60 | ||
|
|
36d11c969f | ||
|
|
f76ce5d3bb | ||
|
|
0df454481e | ||
|
|
83c1a30cfb | ||
|
|
6cbd1479c6 | ||
|
|
3e6e438920 | ||
|
|
560886eb90 | ||
|
|
340bb5cef6 | ||
|
|
44a7c1d4a5 | ||
|
|
519c49f175 | ||
|
|
c96ffefa42 | ||
|
|
490ca8ad5a | ||
|
|
e385f87d6c | ||
|
|
58de53123a | ||
|
|
4f365c1716 | ||
|
|
981177da23 | ||
|
|
088bea9ccd | ||
|
|
36350f179e | ||
|
|
902f08c1bc | ||
|
|
47ad206ccd | ||
|
|
9f51546023 | ||
|
|
f6d679f056 | ||
|
|
93c45e88e7 | ||
|
|
da189da9ae | ||
|
|
c40a33cb48 | ||
|
|
9846beee7d | ||
|
|
81685f9132 | ||
|
|
14123d25c2 | ||
|
|
928819ffbd | ||
|
|
7f2f9636f5 | ||
|
|
b49fe146ad | ||
|
|
98bbd4136b | ||
|
|
d8d02f71ba | ||
|
|
26980df2b9 | ||
|
|
ffe39473d0 | ||
|
|
6af8d152ee | ||
|
|
de846a8f7a | ||
|
|
8e31316e3d | ||
|
|
fb6edb3243 | ||
|
|
244bd9256f | ||
|
|
1f61fd383c | ||
|
|
ce294ce0c1 | ||
|
|
dcbdc0ac51 | ||
|
|
daea06586d | ||
|
|
9c8bf2587b | ||
|
|
9871cb04ea | ||
|
|
7dc093815f | ||
|
|
087697106c | ||
|
|
9beebc7bfe | ||
|
|
4a948b7aae | ||
|
|
0d3bc21e97 | ||
|
|
7496894ae6 | ||
|
|
918d7217a9 | ||
|
|
2103d583f9 | ||
|
|
837c446926 | ||
|
|
480ea54ee0 | ||
|
|
97e7c34cb6 | ||
|
|
fe65b149f5 | ||
|
|
4106b97174 | ||
|
|
8648954b94 | ||
|
|
9f1fae0955 | ||
|
|
1d631c3c6d | ||
|
|
727161f1db | ||
|
|
bf5f628769 | ||
|
|
8563a5785f | ||
|
|
4082634e6d | ||
|
|
a74adb5865 | ||
|
|
2e4d7301f2 | ||
|
|
94845222ad | ||
|
|
7f6ac2deee | ||
|
|
a054aa9c52 | ||
|
|
22cb59b88c | ||
|
|
6968772a31 | ||
|
|
004f4b51d1 | ||
|
|
8c8dd7b4bc | ||
|
|
9778289d33 | ||
|
|
a43caf08a6 | ||
|
|
01e550fac9 | ||
|
|
ad4dd6a060 | ||
|
|
849d99b0dc | ||
|
|
f5df5f71a3 | ||
|
|
429be0a5ae | ||
|
|
148e4ec555 | ||
|
|
bb22f4d6a3 | ||
|
|
f94703360b | ||
|
|
f26bec1a5a | ||
|
|
d065f4ae62 | ||
|
|
ed2c3e626b | ||
|
|
1927f92358 | ||
|
|
939144174c | ||
|
|
59bcbe7fef | ||
|
|
8e00fedc67 | ||
|
|
0ac879ae0b | ||
|
|
22d1a18d22 | ||
|
|
ca203bff9b | ||
|
|
e01d16ce82 | ||
|
|
93b6b9835c | ||
|
|
d0ac5388d9 | ||
|
|
9097d646ca | ||
|
|
596a28e1fb | ||
|
|
5205ff5c43 | ||
|
|
c420bf5f4f | ||
|
|
18844e15dc | ||
|
|
af2f5b7348 | ||
|
|
bcbf0f0e26 | ||
|
|
4d460d4bc3 | ||
|
|
92f6f3ac0d | ||
|
|
bc63d246c8 | ||
|
|
b25f272d72 | ||
|
|
e3a3305adb | ||
|
|
c655c4e106 | ||
|
|
7fe8cdaa34 | ||
|
|
df97985048 | ||
|
|
3779675816 | ||
|
|
0005aad5b5 | ||
|
|
98c18517e2 | ||
|
|
e4dee935ce | ||
|
|
f8cb44fb3c | ||
|
|
101901fdb8 | ||
|
|
b8579d2040 | ||
|
|
3fca3df756 | ||
|
|
2f5db85997 | ||
|
|
e0d4361875 | ||
|
|
30bafc43bd | ||
|
|
3530437b48 | ||
|
|
81db42942c | ||
|
|
6cb0d9e0b5 | ||
|
|
19f7e36753 | ||
|
|
a963f97520 | ||
|
|
ad2d48e9b7 | ||
|
|
5c0d67ca14 | ||
|
|
3467329a7c | ||
|
|
d73fa370f3 | ||
|
|
78fd0a4870 | ||
|
|
3162bb475d | ||
|
|
c17503abd5 | ||
|
|
3433ee8171 | ||
|
|
344297b0a7 | ||
|
|
947456628e | ||
|
|
80dd6c111d | ||
|
|
b70188ba4b | ||
|
|
c6064aa2b4 | ||
|
|
6596f864be | ||
|
|
f61a40efb8 | ||
|
|
b049f0b480 | ||
|
|
b2641d29c1 | ||
|
|
7b8cfc768d | ||
|
|
04860567f7 | ||
|
|
b16edb5a99 | ||
|
|
15a995b2e7 | ||
|
|
f57e26c54e | ||
|
|
2b7bc1cd9f | ||
|
|
614a2f66a3 | ||
|
|
9047b02c92 | ||
|
|
e73d0477bb | ||
|
|
2b1e623eb4 | ||
|
|
c366d555e9 | ||
|
|
7efbd62730 | ||
|
|
b77c1d0af8 | ||
|
|
f8810ea6a8 | ||
|
|
40dd667211 | ||
|
|
848b572864 | ||
|
|
7c858fbccd | ||
|
|
a1814ea37d | ||
|
|
5892a1dbe2 | ||
|
|
29f524f432 | ||
|
|
4ec588ebd7 | ||
|
|
efdef61477 | ||
|
|
fe2b9f8c12 | ||
|
|
c6be55eb55 | ||
|
|
4c69925b84 | ||
|
|
bc6407df0a | ||
|
|
01982a8d0a | ||
|
|
b995cd6257 | ||
|
|
b16d7b7a95 | ||
|
|
42aea701d3 | ||
|
|
5f56c85182 | ||
|
|
52b4eb8950 | ||
|
|
eeb2b42a0f | ||
|
|
90772033d1 | ||
|
|
dadeb4d2a9 | ||
|
|
60a5029c88 | ||
|
|
d7ba16b48b | ||
|
|
fca9befa63 | ||
|
|
187cbde0db | ||
|
|
f5ae5cade8 | ||
|
|
3e66c28aff | ||
|
|
89703a1aef | ||
|
|
cba31617e9 | ||
|
|
a3eeb46961 | ||
|
|
128bd76f20 | ||
|
|
c0355fd2c6 | ||
|
|
a5fd440e25 | ||
|
|
592ef8be2a | ||
|
|
3bcc1c7297 | ||
|
|
3b44c3acd1 | ||
|
|
ec4911643a | ||
|
|
f4fedbab44 | ||
|
|
553d441ecc | ||
|
|
1946116438 | ||
|
|
ab28515fba | ||
|
|
4dc11fb95e | ||
|
|
e27094e0f3 | ||
|
|
88302201eb | ||
|
|
8afb172e83 | ||
|
|
562d024623 | ||
|
|
50b094547c | ||
|
|
a6c1e50985 | ||
|
|
96772bdfc6 | ||
|
|
ed154d373c | ||
|
|
a5e862ce36 | ||
|
|
ae55964bd9 | ||
|
|
c162309f41 | ||
|
|
62c667f1a0 | ||
|
|
3d08eae8e4 | ||
|
|
2af5a0a6dd | ||
|
|
6d24b04235 | ||
|
|
3ee8103353 | ||
|
|
1296165fce | ||
|
|
7100c22dc4 | ||
|
|
5718c0f5b8 | ||
|
|
25ebddfa1c | ||
|
|
2c0558fe23 | ||
|
|
7192108fc1 | ||
|
|
847696c342 | ||
|
|
912ae1fc87 | ||
|
|
a86f75d31d | ||
|
|
fe1e25b5c7 | ||
|
|
9b241b596a | ||
|
|
53b9c8d5bb | ||
|
|
2946bc9d72 | ||
|
|
67a20e212d | ||
|
|
a9ace366eb | ||
|
|
df3469efba | ||
|
|
0a3bbb8554 | ||
|
|
a15b9f5d3b | ||
|
|
e6334b0716 | ||
|
|
7a835baa5a | ||
|
|
c9c21a5728 | ||
|
|
956959fc32 | ||
|
|
6f67f74638 | ||
|
|
b3dd4543b7 | ||
|
|
4f17a28ac5 | ||
|
|
90736f367a | ||
|
|
9af88bd482 | ||
|
|
13b89f4934 | ||
|
|
d00a00d142 | ||
|
|
e662c39e16 | ||
|
|
95ef131285 | ||
|
|
7476f170f6 | ||
|
|
3b6bd55d1e | ||
|
|
10dbc9e884 | ||
|
|
860f619dfe | ||
|
|
17ddc9ee0c | ||
|
|
949689c318 | ||
|
|
86a2aac011 | ||
|
|
d0a402f201 | ||
|
|
05772d5365 | ||
|
|
c2a68f5147 | ||
|
|
697ca1c7be | ||
|
|
409346952f | ||
|
|
f4b3539d77 | ||
|
|
c12166c1a1 | ||
|
|
8d20f003cb | ||
|
|
88f857a2f0 | ||
|
|
fb7faadd99 | ||
|
|
5c8d6752fb | ||
|
|
dda81fbc2c | ||
|
|
c40dff5d63 | ||
|
|
6f07b54772 | ||
|
|
ce0f1dfcb6 | ||
|
|
9a3a5d48eb | ||
|
|
4a759eda02 | ||
|
|
26badf201d | ||
|
|
384f27cd6d | ||
|
|
ac1c5f9f58 | ||
|
|
8ad058fdf4 | ||
|
|
9024c3c67a | ||
|
|
fc81a47499 | ||
|
|
a331452076 | ||
|
|
b1c6e8168e | ||
|
|
b41cc0226e | ||
|
|
450429ddd5 | ||
|
|
f7b24f4b4b | ||
|
|
294c985380 | ||
|
|
720964b901 | ||
|
|
8895c8a987 | ||
|
|
740dcd72a2 | ||
|
|
ffd442624f | ||
|
|
088fd85694 | ||
|
|
d5b68d69d3 | ||
|
|
bb0f7bb393 | ||
|
|
d86a108f18 | ||
|
|
7828ed2d9e | ||
|
|
ebf14f50fb | ||
|
|
1546ff615b | ||
|
|
46cf1fb597 | ||
|
|
8bf8655054 | ||
|
|
a6d84948e2 | ||
|
|
fac20a1f97 | ||
|
|
c65586b5e1 | ||
|
|
b27b018b06 | ||
|
|
403da1e632 | ||
|
|
2371ec1f9e | ||
|
|
5e3ec2d34b | ||
|
|
78d84644c9 | ||
|
|
0cd0f8015a | ||
|
|
4b5424f695 | ||
|
|
a1d59040f7 | ||
|
|
0306398072 | ||
|
|
a7e0bf9013 | ||
|
|
ddb988cd83 | ||
|
|
04b54353f1 | ||
|
|
f058107c05 | ||
|
|
6b5b0815d7 | ||
|
|
8388497038 | ||
|
|
825b1113b6 | ||
|
|
9074ef792f | ||
|
|
0946f28511 | ||
|
|
23765cd4f5 | ||
|
|
e20c6468d0 | ||
|
|
b90516de1d | ||
|
|
ec5cc0f00f | ||
|
|
5dda5a976e | ||
|
|
915da9ae13 | ||
|
|
8652464f4e | ||
|
|
ce6ce1c1f8 | ||
|
|
39efe67e55 | ||
|
|
748ffa00f3 | ||
|
|
e8d9df2b0e | ||
|
|
17396d67de | ||
|
|
edd6a86714 | ||
|
|
85b4012c56 | ||
|
|
7d98433502 | ||
|
|
23774ae03b | ||
|
|
0dedbcdd71 | ||
|
|
4bdd08887e | ||
|
|
1fd8ebf386 | ||
|
|
d2fc3e749c | ||
|
|
71fbcbceaf | ||
|
|
27347b2088 | ||
|
|
599993d1a5 | ||
|
|
bf359cb8e3 | ||
|
|
509a704410 | ||
|
|
1f48e2b01f | ||
|
|
8b25b1eee6 | ||
|
|
3bbf30ff5f | ||
|
|
83613726d1 | ||
|
|
254b6a17f3 | ||
|
|
796e12bd70 | ||
|
|
ddbe17d3f6 | ||
|
|
591ec36f4a | ||
|
|
41eceb72ef | ||
|
|
0a5f094025 | ||
|
|
ca0f3ba262 | ||
|
|
30f4e782db | ||
|
|
192158ef1a | ||
|
|
602456db40 | ||
|
|
536e45668f | ||
|
|
10bf05ab0d | ||
|
|
5ad1af69e4 | ||
|
|
48f2911434 | ||
|
|
dbb0d6349a | ||
|
|
ac3598f12a | ||
|
|
66201be5ca | ||
|
|
ac0b0b652e | ||
|
|
d89ee2df42 | ||
|
|
418e248e5e | ||
|
|
8c2b141049 | ||
|
|
2f8e07302b | ||
|
|
c3776240b6 | ||
|
|
e370872ec1 | ||
|
|
d4e978369a | ||
|
|
8d5d7f5237 | ||
|
|
5cd498fbe9 | ||
|
|
250f515f08 | ||
|
|
0ec0a9e313 | ||
|
|
184f42ef03 | ||
|
|
499517418d | ||
|
|
606b9c1a6d | ||
|
|
971e954a54 | ||
|
|
e3aaf3219d | ||
|
|
0eea1c0e40 | ||
|
|
0773819778 | ||
|
|
170869b7db | ||
|
|
5dc54782e5 | ||
|
|
97b26fbefe | ||
|
|
686cc58d6c | ||
|
|
76a59759b2 | ||
|
|
93245a24b5 | ||
|
|
6a22ea1c7d | ||
|
|
56a02409c8 | ||
|
|
edeafd5a53 | ||
|
|
f67490b69b | ||
|
|
b76e34fb7b | ||
|
|
ddbda5032b | ||
|
|
5898d34b0a | ||
|
|
b0c02341ff | ||
|
|
19cbc8c33b | ||
|
|
02e61ef5d3 | ||
|
|
8d5d18064d | ||
|
|
c5ef7ebd27 | ||
|
|
047a3e0e8c | ||
|
|
13b23f840b | ||
|
|
147f6012b2 | ||
|
|
2c315595f0 | ||
|
|
20405c84ac | ||
|
|
0bc59b97de | ||
|
|
a3a3bdc7eb | ||
|
|
e767f30886 | ||
|
|
e8c250a03c | ||
|
|
d6725fc1ca | ||
|
|
8ec998ff30 | ||
|
|
23cc0c7f39 | ||
|
|
19b8bd6aa8 | ||
|
|
ed57e7c6b0 | ||
|
|
9f489c9f27 | ||
|
|
f036989361 | ||
|
|
6afa8141c0 | ||
|
|
587964c6f1 | ||
|
|
7aea82a273 | ||
|
|
20f946ccaf | ||
|
|
e5e972231c | ||
|
|
bfa80157f2 | ||
|
|
99b1b079d0 | ||
|
|
5697d549a8 | ||
|
|
754d2874e7 | ||
|
|
06de58ff8b | ||
|
|
a0b3527710 | ||
|
|
df24f48fa1 | ||
|
|
13d53590b2 | ||
|
|
5857f7b9a7 | ||
|
|
a5ea0cd41f | ||
|
|
d677934417 | ||
|
|
ba87a0b63c | ||
|
|
b725bb3dd1 | ||
|
|
c34ba3deb5 | ||
|
|
68b13340fb | ||
|
|
8831999ea6 | ||
|
|
c1853f8b84 | ||
|
|
2b9b7e2853 | ||
|
|
d3b18debf9 | ||
|
|
b01eb28d42 | ||
|
|
02019dd16c | ||
|
|
7be12f5ff6 | ||
|
|
a90d59b6ba | ||
|
|
e7fa156254 | ||
|
|
a8ab6b1c43 | ||
|
|
25ed7c890b | ||
|
|
85e3b63f05 | ||
|
|
a37bac1956 | ||
|
|
818a978dfc | ||
|
|
180aeb7d8e | ||
|
|
0764fa7292 | ||
|
|
17bf533ed7 | ||
|
|
d7eae1c1a0 | ||
|
|
7f2d979255 | ||
|
|
46b419ea8b | ||
|
|
b30b527ff9 | ||
|
|
41b1bfc504 | ||
|
|
f4f14a7507 | ||
|
|
61c29213a7 | ||
|
|
e6d7639209 | ||
|
|
3c07a186b2 | ||
|
|
8a725250a9 | ||
|
|
502b8a6073 | ||
|
|
6212c6f80f | ||
|
|
b03e3b8d4a | ||
|
|
a98e34d190 | ||
|
|
bf8d8b6e63 | ||
|
|
57599f7a98 | ||
|
|
ffccce7ffc | ||
|
|
bbd5d050a9 | ||
|
|
71a96fdcbf | ||
|
|
221e3c6c9c | ||
|
|
fb1679d572 | ||
|
|
c19065f112 | ||
|
|
f2b04a077e | ||
|
|
8e7841c880 | ||
|
|
1873490b24 | ||
|
|
4d231953f4 | ||
|
|
aa4c399657 | ||
|
|
1f99d18982 | ||
|
|
be37178ef8 | ||
|
|
fad86c655e | ||
|
|
4a7958586e | ||
|
|
f44ecd0891 | ||
|
|
3d0392d668 | ||
|
|
d300d2605b | ||
|
|
66cce6a2f2 | ||
|
|
65e3c6bfbb | ||
|
|
2a39060912 | ||
|
|
8714e80978 | ||
|
|
98de53f60b | ||
|
|
41e11e9a0e | ||
|
|
e7a4eac8bd | ||
|
|
1589a131db | ||
|
|
7d84f0e650 | ||
|
|
86fb0e317f | ||
|
|
32088d5ef7 | ||
|
|
63de88dd57 | ||
|
|
153a6440dc | ||
|
|
8937ed2269 | ||
|
|
02e922b56f | ||
|
|
bf9e901ab9 | ||
|
|
1234ef8de2 | ||
|
|
41697a7b1b | ||
|
|
912e265bc0 | ||
|
|
96ee6fb064 | ||
|
|
788dba8ef3 | ||
|
|
fdde9c4681 | ||
|
|
f195e73d38 | ||
|
|
b0d9ffc6a1 | ||
|
|
e17619841d | ||
|
|
eb6a7cf3b9 | ||
|
|
9901e2d72e | ||
|
|
1be4e23b68 | ||
|
|
e78094cc0a | ||
|
|
bcf961c0b0 | ||
|
|
f84a4c9753 | ||
|
|
df56ca0236 | ||
|
|
de0cd0ec67 | ||
|
|
67c30245c4 | ||
|
|
1f72757591 | ||
|
|
35c2fdf6af | ||
|
|
d1ecd841be | ||
|
|
828a49697c | ||
|
|
0551495501 | ||
|
|
2bbffe4a68 | ||
|
|
281ad90e39 | ||
|
|
ed50976a07 | ||
|
|
a3400037d9 | ||
|
|
f0d82f75bc | ||
|
|
349cb80e90 | ||
|
|
c263ee39af | ||
|
|
e99bc52756 | ||
|
|
7944b2b8e9 | ||
|
|
ca6ae746c1 | ||
|
|
deabac18b2 | ||
|
|
5cf8681c61 | ||
|
|
ca7ede8f96 | ||
|
|
4969682d52 | ||
|
|
8002fe0dd5 | ||
|
|
7dfdf965b7 | ||
|
|
b408795dd6 | ||
|
|
a5a099336b | ||
|
|
4ae56fc004 | ||
|
|
3f71c09b7b | ||
|
|
bd50a7f1ab | ||
|
|
51e4c45e5c | ||
|
|
e3fae49add | ||
|
|
610215ab60 | ||
|
|
74acbda435 | ||
|
|
25c4af777c | ||
|
|
ec186e6324 | ||
|
|
150b7a98f3 | ||
|
|
8ae7c1cff0 | ||
|
|
7f1d0eef98 | ||
|
|
1179ab33f2 | ||
|
|
a09faa1c10 | ||
|
|
c0319d9b2f | ||
|
|
4870cd2921 | ||
|
|
d4280ec68b | ||
|
|
52cdc11927 | ||
|
|
8345b8c9ce | ||
|
|
c56f0677c3 | ||
|
|
00e9e1421e | ||
|
|
93c72c6e6c | ||
|
|
9cea930dbd | ||
|
|
7b9bd70729 | ||
|
|
5115c7a100 | ||
|
|
5634494e64 | ||
|
|
aa8bd4abf1 | ||
|
|
17fd69dd7f | ||
|
|
1d9dae374b | ||
|
|
cb2241ad91 | ||
|
|
d8a7e9abc8 | ||
|
|
969abc3f29 | ||
|
|
766fdc8a1f | ||
|
|
4c37c20d76 | ||
|
|
7d314398e1 | ||
|
|
b69191e3a8 | ||
|
|
b27c6b3596 | ||
|
|
5453835963 | ||
|
|
4d55ba057c | ||
|
|
325c01242c | ||
|
|
45b32bca89 | ||
|
|
7620049214 | ||
|
|
3553495a60 | ||
|
|
3ce6db61d5 | ||
|
|
798ff32c40 | ||
|
|
430cee8bda | ||
|
|
1fe3fb25a6 | ||
|
|
685ed87581 | ||
|
|
ea3ea1eee7 | ||
|
|
c9edcb909b | ||
|
|
35bfc9f069 | ||
|
|
c4aec194b9 | ||
|
|
e8547b16f6 | ||
|
|
2bbe08cee0 | ||
|
|
0a0c369b88 | ||
|
|
5d2f454a94 | ||
|
|
04bcc5c879 | ||
|
|
d4db16665f | ||
|
|
20b7a494f6 | ||
|
|
fbdce3ad89 | ||
|
|
4fc8807f02 | ||
|
|
83075bfb5c | ||
|
|
4074ec0425 | ||
|
|
8e1694dd0f | ||
|
|
911df18855 | ||
|
|
6b049e93f8 | ||
|
|
a335dcc379 | ||
|
|
c6478c8a79 | ||
|
|
cc9d40cb60 | ||
|
|
0a6b7f9a1b | ||
|
|
daa1fb9a7a | ||
|
|
b7d543290b | ||
|
|
ea852b60ac | ||
|
|
ed341988ea | ||
|
|
057b6c8e30 | ||
|
|
44444fe071 | ||
|
|
797330d6ab | ||
|
|
a630d5b5f5 | ||
|
|
eb3dc82b5d | ||
|
|
34ed18d562 | ||
|
|
1ce02ee313 | ||
|
|
2a26a0188c | ||
|
|
50cb05d1b1 | ||
|
|
6e739ac453 | ||
|
|
7aa2fd9f0e | ||
|
|
8e254e1b03 | ||
|
|
1ad9d717ff | ||
|
|
104658e43a | ||
|
|
e7e4b995bf | ||
|
|
b35b54f2c2 | ||
|
|
f80aeb1d1d | ||
|
|
6a756ab3b6 | ||
|
|
58a697bed1 | ||
|
|
280960ac18 | ||
|
|
0640ff13aa | ||
|
|
545505691f | ||
|
|
11fcf81321 | ||
|
|
c565b37dc8 | ||
|
|
3d18495270 | ||
|
|
419e4e63e9 | ||
|
|
724aa2bf65 | ||
|
|
573fa8aeb3 | ||
|
|
8a672e34c5 | ||
|
|
bc49211dab | ||
|
|
4ef9c3667e | ||
|
|
6babe516ac | ||
|
|
e0b258ef7e | ||
|
|
ff0c3a89b1 | ||
|
|
2511b81048 | ||
|
|
6ffcd94edc | ||
|
|
2fcf73c812 | ||
|
|
dee0608af9 | ||
|
|
d11860a383 | ||
|
|
1c05115bf5 | ||
|
|
d7e7382d0b | ||
|
|
872388f6e3 | ||
|
|
1215ef920b | ||
|
|
d19d5a23ea | ||
|
|
f49a779f1d | ||
|
|
d8bf5b80e1 | ||
|
|
69483b9353 | ||
|
|
14e8548989 | ||
|
|
4abd93b661 | ||
|
|
5d925af76f | ||
|
|
b999c6064a | ||
|
|
94e3576978 | ||
|
|
7a22406a2d | ||
|
|
e60684494f | ||
|
|
9db28ed779 | ||
|
|
6fd8c5cee7 | ||
|
|
787ec43266 | ||
|
|
a4efc63bf2 | ||
|
|
80a8f1437e | ||
|
|
fcca94169d | ||
|
|
d1924088e3 | ||
|
|
fd31afe09c | ||
|
|
7a763712c5 | ||
|
|
7216be5da7 | ||
|
|
711b0a291b | ||
|
|
dfc96496c8 | ||
|
|
2a1c5ef333 | ||
|
|
9755209499 | ||
|
|
0b26e537d4 | ||
|
|
98c6233ec3 | ||
|
|
f711706b1a | ||
|
|
cee7789ab6 | ||
|
|
8a06c4380d | ||
|
|
72ecf7a288 | ||
|
|
ef98c7502d | ||
|
|
03d0e74b65 | ||
|
|
5b8fdc0364 | ||
|
|
593b4bd137 | ||
|
|
267e12d058 | ||
|
|
4a5e39b651 | ||
|
|
ea24fa5b78 | ||
|
|
bb2bb128f7 | ||
|
|
94e8a856d7 | ||
|
|
4c19fbf98e | ||
|
|
60f8938bfa | ||
|
|
55679662b5 | ||
|
|
53df959e49 | ||
|
|
8e6ef9966f | ||
|
|
1d52fceafa | ||
|
|
99186ed864 | ||
|
|
383931d484 | ||
|
|
0b49a54cb3 | ||
|
|
705c0f1891 | ||
|
|
544c3ffc95 | ||
|
|
33f252a45d | ||
|
|
f55d82a015 | ||
|
|
8cf33fdef0 | ||
|
|
f858d98811 | ||
|
|
2a6165d440 | ||
|
|
4586528c40 | ||
|
|
23a07baa19 | ||
|
|
f9040ca932 | ||
|
|
4cea7f0237 | ||
|
|
b1847d5e98 | ||
|
|
9ce4d2e952 | ||
|
|
247078e06d | ||
|
|
a0cd72de28 | ||
|
|
e467f569f0 | ||
|
|
e31c7b7dfc | ||
|
|
dc2e0c832b | ||
|
|
7ddf51bb51 | ||
|
|
8fb3856665 | ||
|
|
183dd74f3e | ||
|
|
4f29039b41 | ||
|
|
102fcbec20 | ||
|
|
d00e5212c7 | ||
|
|
0e6bfb62cd | ||
|
|
f576e8f635 | ||
|
|
e6dc10a440 | ||
|
|
aa930fb6b6 | ||
|
|
f327ed87e9 | ||
|
|
2de9be0589 | ||
|
|
345cde8645 | ||
|
|
cf152af9ae | ||
|
|
d6333dcfd9 | ||
|
|
0121f799f0 | ||
|
|
82c39580df | ||
|
|
53a578a46f | ||
|
|
62612ef80b | ||
|
|
61ac874c4c | ||
|
|
976b200ff6 | ||
|
|
852343b6d8 | ||
|
|
c56af9d52b | ||
|
|
05f18e2828 | ||
|
|
72804caab2 | ||
|
|
80cbe5c7c9 | ||
|
|
21892d1236 | ||
|
|
13824624f8 | ||
|
|
0fd72ecbab | ||
|
|
f848cb1546 | ||
|
|
633854081a | ||
|
|
4fed9a581b | ||
|
|
e9c1202aaa | ||
|
|
0a7ae279d0 | ||
|
|
0de2696543 | ||
|
|
a7dc239b71 | ||
|
|
fe0e6990f5 | ||
|
|
5ba65e92d9 | ||
|
|
a1452b52c9 | ||
|
|
dd2aa23a5f | ||
|
|
0e0359ba7d | ||
|
|
93b1b7aded | ||
|
|
9472dc6a53 | ||
|
|
67b681854e | ||
|
|
7b5990833e | ||
|
|
b6d5d04589 | ||
|
|
fdfbb3e944 | ||
|
|
faa7a3e37f | ||
|
|
23748b82bb | ||
|
|
bccb6f578a | ||
|
|
de8a5d6e9e | ||
|
|
a8eb3f7961 | ||
|
|
2dc85f5a42 | ||
|
|
82518b351d | ||
|
|
68f34a1683 | ||
|
|
bc6b72a422 | ||
|
|
599e28e1cb | ||
|
|
ee6b2ba6c6 | ||
|
|
0877b3e2af | ||
|
|
d1edb1e32a | ||
|
|
d1e6b8dd10 | ||
|
|
b32fc3bfdd | ||
|
|
1e24417db0 | ||
|
|
fb9387ecc5 | ||
|
|
6c5f4cdb70 | ||
|
|
aabacb7454 | ||
|
|
b5da84479e | ||
|
|
88d9361050 | ||
|
|
1d90388ffc | ||
|
|
b3c43ce31f | ||
|
|
6d9d22d422 | ||
|
|
86be1f56d0 | ||
|
|
a0c81ffd7a | ||
|
|
ec1dc42e58 | ||
|
|
866eaed73d | ||
|
|
a18374e1ad | ||
|
|
f7afcb3b24 | ||
|
|
3adcae783c | ||
|
|
73b40dd2e7 | ||
|
|
1e12614f9a | ||
|
|
aeaa7c699a | ||
|
|
f1c56b7254 | ||
|
|
e72e0d0646 | ||
|
|
5719d334aa | ||
|
|
bcb6b85333 | ||
|
|
5d765413ef | ||
|
|
efb2e5e7a8 | ||
|
|
5d5e346199 | ||
|
|
08a74890da | ||
|
|
0545b9c7f2 | ||
|
|
bbf7d32676 | ||
|
|
e83f4ae974 | ||
|
|
9b0d01e03f | ||
|
|
eae0d90a1e | ||
|
|
90c09a7650 | ||
|
|
aecf080211 | ||
|
|
8517420356 | ||
|
|
376be1f009 | ||
|
|
0021e76649 | ||
|
|
d440c4bc43 | ||
|
|
50840b2105 | ||
|
|
7502c6b6c0 | ||
|
|
919c32f0cc | ||
|
|
a28c951272 | ||
|
|
13d7c5a9a9 | ||
|
|
5f1383344d | ||
|
|
48f43d3eb1 | ||
|
|
4ac2141307 | ||
|
|
719d8cac97 | ||
|
|
99cbe53a8e | ||
|
|
a36af1bfac | ||
|
|
8b6aa319bf | ||
|
|
a16d321e1a | ||
|
|
74e70278e2 | ||
|
|
1332e24a2c | ||
|
|
5ab78ec461 | ||
|
|
ce701d3c31 | ||
|
|
5fca1be44d | ||
|
|
0bd4c333bd | ||
|
|
c6ed880732 | ||
|
|
da0f3c6cce | ||
|
|
e5d12d346a | ||
|
|
478e2e726b | ||
|
|
dbdac3707b | ||
|
|
bd89a88e34 | ||
|
|
d322d83745 | ||
|
|
463a581ab9 | ||
|
|
eae4bd222a | ||
|
|
a7bb7fc14d | ||
|
|
c047aa47eb | ||
|
|
61bca56316 | ||
|
|
9a37323eb8 | ||
|
|
99a54369bf | ||
|
|
f7533dfc5c | ||
|
|
ee7d95272d | ||
|
|
2b9b1d12e6 | ||
|
|
2cbb5c7d8e | ||
|
|
9686c7babe | ||
|
|
66bd4c96c4 | ||
|
|
dc47faa4b6 | ||
|
|
55ee0b116d | ||
|
|
c6957c08bc | ||
|
|
8fe6a323d8 | ||
|
|
8e51590c32 | ||
|
|
ae066d5627 | ||
|
|
6760279916 | ||
|
|
3c208050b0 | ||
|
|
bbc7c9fb37 | ||
|
|
e1c3862586 | ||
|
|
c24b7cb7bd | ||
|
|
c91e16549d | ||
|
|
6e70aca458 | ||
|
|
d9ffd0ac8e | ||
|
|
4641f73d19 | ||
|
|
9f0051c21f | ||
|
|
0331cb09e8 | ||
|
|
2f8946f86c | ||
|
|
88a3df4008 | ||
|
|
0adf514bd6 | ||
|
|
a1b5a2abcb | ||
|
|
068c62c6fe | ||
|
|
0e9f14f969 | ||
|
|
78315fd388 | ||
|
|
0ab69002df | ||
|
|
1eec1239ec | ||
|
|
57f4067fbf | ||
|
|
f4a9221232 | ||
|
|
3d4a75148d | ||
|
|
c2c5bd844d | ||
|
|
98a2f23024 | ||
|
|
c955897d1b | ||
|
|
9624efa21e | ||
|
|
831638210d | ||
|
|
cfdb0925ce | ||
|
|
83db3eddd9 | ||
|
|
cc2c5a544e | ||
|
|
8fba8c2800 | ||
|
|
51d1da8460 | ||
|
|
2f1257056d | ||
|
|
2f8f6967bf | ||
|
|
246527e618 | ||
|
|
3857cc9c83 | ||
|
|
a59a8c563e | ||
|
|
856829bcbb | ||
|
|
dd2b931f61 | ||
|
|
39beccbbb0 | ||
|
|
ff626b428f | ||
|
|
3915e1f012 | ||
|
|
7b460b6224 | ||
|
|
8fb8e79730 | ||
|
|
79bbc475f4 | ||
|
|
cef023283b | ||
|
|
d4fda79ada | ||
|
|
ff0bdcf4cd | ||
|
|
bfbc313144 | ||
|
|
31f2376f15 | ||
|
|
f76ecb6604 | ||
|
|
298cc58433 | ||
|
|
825c0593e1 | ||
|
|
87ed1dc3e3 | ||
|
|
67e9db021c | ||
|
|
3922950951 | ||
|
|
9c4aa0ba53 | ||
|
|
f5f1651b31 | ||
|
|
32f4e4ca13 | ||
|
|
962e0c4c33 | ||
|
|
2c01bc5795 | ||
|
|
0651f7cb3c | ||
|
|
01ac59ce2a | ||
|
|
c1fd597757 | ||
|
|
e79e244eee | ||
|
|
68ecc08111 | ||
|
|
3b5fbc359f | ||
|
|
583e5ea47f | ||
|
|
7b647c3fae | ||
|
|
a8b76c617c | ||
|
|
1bd8985dff | ||
|
|
25b5a6c4ae |
@@ -327,6 +327,7 @@ esphome/components/opentherm/* @olegtarasov
|
|||||||
esphome/components/openthread/* @mrene
|
esphome/components/openthread/* @mrene
|
||||||
esphome/components/opt3001/* @ccutrer
|
esphome/components/opt3001/* @ccutrer
|
||||||
esphome/components/ota/* @esphome/core
|
esphome/components/ota/* @esphome/core
|
||||||
|
esphome/components/ota_base/* @esphome/core
|
||||||
esphome/components/output/* @esphome/core
|
esphome/components/output/* @esphome/core
|
||||||
esphome/components/packet_transport/* @clydebarrow
|
esphome/components/packet_transport/* @clydebarrow
|
||||||
esphome/components/pca6416a/* @Mat931
|
esphome/components/pca6416a/* @Mat931
|
||||||
|
|||||||
@@ -3493,7 +3493,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite
|
|||||||
}
|
}
|
||||||
void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
|
void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_enum<enums::LogLevel>(1, this->level);
|
buffer.encode_enum<enums::LogLevel>(1, this->level);
|
||||||
buffer.encode_string(3, this->message);
|
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->message.data()), this->message.size());
|
||||||
buffer.encode_bool(4, this->send_failed);
|
buffer.encode_bool(4, this->send_failed);
|
||||||
}
|
}
|
||||||
void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const {
|
void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const {
|
||||||
@@ -3529,7 +3529,9 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->key); }
|
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const {
|
||||||
|
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->key.data()), this->key.size());
|
||||||
|
}
|
||||||
void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const {
|
void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_string_field(total_size, 1, this->key, false);
|
ProtoSize::add_string_field(total_size, 1, this->key, false);
|
||||||
}
|
}
|
||||||
@@ -4266,7 +4268,7 @@ bool CameraImageResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
|||||||
}
|
}
|
||||||
void CameraImageResponse::encode(ProtoWriteBuffer buffer) const {
|
void CameraImageResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_fixed32(1, this->key);
|
buffer.encode_fixed32(1, this->key);
|
||||||
buffer.encode_string(2, this->data);
|
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
buffer.encode_bool(3, this->done);
|
buffer.encode_bool(3, this->done);
|
||||||
}
|
}
|
||||||
void CameraImageResponse::calculate_size(uint32_t &total_size) const {
|
void CameraImageResponse::calculate_size(uint32_t &total_size) const {
|
||||||
@@ -6784,7 +6786,7 @@ void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const {
|
|||||||
for (auto &it : this->legacy_data) {
|
for (auto &it : this->legacy_data) {
|
||||||
buffer.encode_uint32(2, it, true);
|
buffer.encode_uint32(2, it, true);
|
||||||
}
|
}
|
||||||
buffer.encode_string(3, this->data);
|
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothServiceData::calculate_size(uint32_t &total_size) const {
|
void BluetoothServiceData::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_string_field(total_size, 1, this->uuid, false);
|
ProtoSize::add_string_field(total_size, 1, this->uuid, false);
|
||||||
@@ -6858,7 +6860,7 @@ bool BluetoothLEAdvertisementResponse::decode_length(uint32_t field_id, ProtoLen
|
|||||||
}
|
}
|
||||||
void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
|
void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_string(2, this->name);
|
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->name.data()), this->name.size());
|
||||||
buffer.encode_sint32(3, this->rssi);
|
buffer.encode_sint32(3, this->rssi);
|
||||||
for (auto &it : this->service_uuids) {
|
for (auto &it : this->service_uuids) {
|
||||||
buffer.encode_string(4, it, true);
|
buffer.encode_string(4, it, true);
|
||||||
@@ -6959,7 +6961,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const {
|
|||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_sint32(2, this->rssi);
|
buffer.encode_sint32(2, this->rssi);
|
||||||
buffer.encode_uint32(3, this->address_type);
|
buffer.encode_uint32(3, this->address_type);
|
||||||
buffer.encode_string(4, this->data);
|
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const {
|
void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
||||||
@@ -7492,7 +7494,7 @@ bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDeli
|
|||||||
void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const {
|
void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_uint32(2, this->handle);
|
buffer.encode_uint32(2, this->handle);
|
||||||
buffer.encode_string(3, this->data);
|
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const {
|
void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
||||||
@@ -7551,7 +7553,7 @@ void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const {
|
|||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_uint32(2, this->handle);
|
buffer.encode_uint32(2, this->handle);
|
||||||
buffer.encode_bool(3, this->response);
|
buffer.encode_bool(3, this->response);
|
||||||
buffer.encode_string(4, this->data);
|
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const {
|
void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
||||||
@@ -7648,7 +7650,7 @@ bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, Proto
|
|||||||
void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
|
void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_uint32(2, this->handle);
|
buffer.encode_uint32(2, this->handle);
|
||||||
buffer.encode_string(3, this->data);
|
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const {
|
void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
||||||
@@ -7750,7 +7752,7 @@ bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLeng
|
|||||||
void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const {
|
void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_uint64(1, this->address);
|
buffer.encode_uint64(1, this->address);
|
||||||
buffer.encode_uint32(2, this->handle);
|
buffer.encode_uint32(2, this->handle);
|
||||||
buffer.encode_string(3, this->data);
|
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
}
|
}
|
||||||
void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const {
|
void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
|
||||||
@@ -8480,7 +8482,7 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const {
|
void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_string(1, this->data);
|
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
|
||||||
buffer.encode_bool(2, this->end);
|
buffer.encode_bool(2, this->end);
|
||||||
}
|
}
|
||||||
void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const {
|
void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
|
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
|
||||||
@@ -61,9 +61,9 @@ void ESP32BLETracker::setup() {
|
|||||||
global_esp32_ble_tracker = this;
|
global_esp32_ble_tracker = this;
|
||||||
|
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
ota::get_global_ota_callback()->add_on_state_callback(
|
ota_base::get_global_ota_callback()->add_on_state_callback(
|
||||||
[this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) {
|
[this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) {
|
||||||
if (state == ota::OTA_STARTED) {
|
if (state == ota_base::OTA_STARTED) {
|
||||||
this->stop_scan();
|
this->stop_scan();
|
||||||
for (auto *client : this->clients_) {
|
for (auto *client : this->clients_) {
|
||||||
client->disconnect();
|
client->disconnect();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
|
from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code
|
||||||
|
from esphome.components.ota_base import OTAComponent
|
||||||
from esphome.config_helpers import merge_config
|
from esphome.config_helpers import merge_config
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
#include "esphome/components/md5/md5.h"
|
#include "esphome/components/md5/md5.h"
|
||||||
#include "esphome/components/network/util.h"
|
#include "esphome/components/network/util.h"
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h" // For OTAComponent and callbacks
|
||||||
#include "esphome/components/ota/ota_backend_arduino_esp32.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_esp32.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_esp8266.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_esp8266.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_libretiny.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_libretiny.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_rp2040.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_rp2040.h"
|
||||||
#include "esphome/components/ota/ota_backend_esp_idf.h"
|
#include "esphome/components/ota_base/ota_backend_esp_idf.h"
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
@@ -23,7 +23,7 @@ static constexpr u_int16_t OTA_BLOCK_SIZE = 8192;
|
|||||||
|
|
||||||
void ESPHomeOTAComponent::setup() {
|
void ESPHomeOTAComponent::setup() {
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
ota::register_ota_platform(this);
|
ota_base::register_ota_platform(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this->server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
|
this->server_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
|
||||||
@@ -94,7 +94,7 @@ void ESPHomeOTAComponent::loop() {
|
|||||||
static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
|
static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
|
||||||
|
|
||||||
void ESPHomeOTAComponent::handle_() {
|
void ESPHomeOTAComponent::handle_() {
|
||||||
ota::OTAResponseTypes error_code = ota::OTA_RESPONSE_ERROR_UNKNOWN;
|
ota_base::OTAResponseTypes error_code = ota_base::OTA_RESPONSE_ERROR_UNKNOWN;
|
||||||
bool update_started = false;
|
bool update_started = false;
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
uint32_t last_progress = 0;
|
uint32_t last_progress = 0;
|
||||||
@@ -102,7 +102,7 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
char *sbuf = reinterpret_cast<char *>(buf);
|
char *sbuf = reinterpret_cast<char *>(buf);
|
||||||
size_t ota_size;
|
size_t ota_size;
|
||||||
uint8_t ota_features;
|
uint8_t ota_features;
|
||||||
std::unique_ptr<ota::OTABackend> backend;
|
std::unique_ptr<ota_base::OTABackend> backend;
|
||||||
(void) ota_features;
|
(void) ota_features;
|
||||||
#if USE_OTA_VERSION == 2
|
#if USE_OTA_VERSION == 2
|
||||||
size_t size_acknowledged = 0;
|
size_t size_acknowledged = 0;
|
||||||
@@ -129,7 +129,7 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
ESP_LOGD(TAG, "Starting update from %s", this->client_->getpeername().c_str());
|
ESP_LOGD(TAG, "Starting update from %s", this->client_->getpeername().c_str());
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0);
|
this->state_callback_.call(ota_base::OTA_STARTED, 0.0f, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!this->readall_(buf, 5)) {
|
if (!this->readall_(buf, 5)) {
|
||||||
@@ -140,16 +140,16 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
|
if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
|
||||||
ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3],
|
ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3],
|
||||||
buf[4]);
|
buf[4]);
|
||||||
error_code = ota::OTA_RESPONSE_ERROR_MAGIC;
|
error_code = ota_base::OTA_RESPONSE_ERROR_MAGIC;
|
||||||
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send OK and version - 2 bytes
|
// Send OK and version - 2 bytes
|
||||||
buf[0] = ota::OTA_RESPONSE_OK;
|
buf[0] = ota_base::OTA_RESPONSE_OK;
|
||||||
buf[1] = USE_OTA_VERSION;
|
buf[1] = USE_OTA_VERSION;
|
||||||
this->writeall_(buf, 2);
|
this->writeall_(buf, 2);
|
||||||
|
|
||||||
backend = ota::make_ota_backend();
|
backend = ota_base::make_ota_backend();
|
||||||
|
|
||||||
// Read features - 1 byte
|
// Read features - 1 byte
|
||||||
if (!this->readall_(buf, 1)) {
|
if (!this->readall_(buf, 1)) {
|
||||||
@@ -160,16 +160,16 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
ESP_LOGV(TAG, "Features: 0x%02X", ota_features);
|
ESP_LOGV(TAG, "Features: 0x%02X", ota_features);
|
||||||
|
|
||||||
// Acknowledge header - 1 byte
|
// Acknowledge header - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_HEADER_OK;
|
buf[0] = ota_base::OTA_RESPONSE_HEADER_OK;
|
||||||
if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
|
if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
|
||||||
buf[0] = ota::OTA_RESPONSE_SUPPORTS_COMPRESSION;
|
buf[0] = ota_base::OTA_RESPONSE_SUPPORTS_COMPRESSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
#ifdef USE_OTA_PASSWORD
|
#ifdef USE_OTA_PASSWORD
|
||||||
if (!this->password_.empty()) {
|
if (!this->password_.empty()) {
|
||||||
buf[0] = ota::OTA_RESPONSE_REQUEST_AUTH;
|
buf[0] = ota_base::OTA_RESPONSE_REQUEST_AUTH;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
md5::MD5Digest md5{};
|
md5::MD5Digest md5{};
|
||||||
md5.init();
|
md5.init();
|
||||||
@@ -220,14 +220,14 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
|
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
ESP_LOGW(TAG, "Auth failed! Passwords do not match");
|
ESP_LOGW(TAG, "Auth failed! Passwords do not match");
|
||||||
error_code = ota::OTA_RESPONSE_ERROR_AUTH_INVALID;
|
error_code = ota_base::OTA_RESPONSE_ERROR_AUTH_INVALID;
|
||||||
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_OTA_PASSWORD
|
#endif // USE_OTA_PASSWORD
|
||||||
|
|
||||||
// Acknowledge auth OK - 1 byte
|
// Acknowledge auth OK - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_AUTH_OK;
|
buf[0] = ota_base::OTA_RESPONSE_AUTH_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
// Read size, 4 bytes MSB first
|
// Read size, 4 bytes MSB first
|
||||||
@@ -243,12 +243,12 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
ESP_LOGV(TAG, "Size is %u bytes", ota_size);
|
ESP_LOGV(TAG, "Size is %u bytes", ota_size);
|
||||||
|
|
||||||
error_code = backend->begin(ota_size);
|
error_code = backend->begin(ota_size);
|
||||||
if (error_code != ota::OTA_RESPONSE_OK)
|
if (error_code != ota_base::OTA_RESPONSE_OK)
|
||||||
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
||||||
update_started = true;
|
update_started = true;
|
||||||
|
|
||||||
// Acknowledge prepare OK - 1 byte
|
// Acknowledge prepare OK - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_UPDATE_PREPARE_OK;
|
buf[0] = ota_base::OTA_RESPONSE_UPDATE_PREPARE_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
// Read binary MD5, 32 bytes
|
// Read binary MD5, 32 bytes
|
||||||
@@ -261,7 +261,7 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
backend->set_update_md5(sbuf);
|
backend->set_update_md5(sbuf);
|
||||||
|
|
||||||
// Acknowledge MD5 OK - 1 byte
|
// Acknowledge MD5 OK - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_BIN_MD5_OK;
|
buf[0] = ota_base::OTA_RESPONSE_BIN_MD5_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
while (total < ota_size) {
|
while (total < ota_size) {
|
||||||
@@ -285,14 +285,14 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_code = backend->write(buf, read);
|
error_code = backend->write(buf, read);
|
||||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code);
|
ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code);
|
||||||
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
||||||
}
|
}
|
||||||
total += read;
|
total += read;
|
||||||
#if USE_OTA_VERSION == 2
|
#if USE_OTA_VERSION == 2
|
||||||
while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
|
while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
|
||||||
buf[0] = ota::OTA_RESPONSE_CHUNK_OK;
|
buf[0] = ota_base::OTA_RESPONSE_CHUNK_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
size_acknowledged += OTA_BLOCK_SIZE;
|
size_acknowledged += OTA_BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
@@ -304,7 +304,7 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
float percentage = (total * 100.0f) / ota_size;
|
float percentage = (total * 100.0f) / ota_size;
|
||||||
ESP_LOGD(TAG, "Progress: %0.1f%%", percentage);
|
ESP_LOGD(TAG, "Progress: %0.1f%%", percentage);
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0);
|
this->state_callback_.call(ota_base::OTA_IN_PROGRESS, percentage, 0);
|
||||||
#endif
|
#endif
|
||||||
// feed watchdog and give other tasks a chance to run
|
// feed watchdog and give other tasks a chance to run
|
||||||
App.feed_wdt();
|
App.feed_wdt();
|
||||||
@@ -313,21 +313,21 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acknowledge receive OK - 1 byte
|
// Acknowledge receive OK - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_RECEIVE_OK;
|
buf[0] = ota_base::OTA_RESPONSE_RECEIVE_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
error_code = backend->end();
|
error_code = backend->end();
|
||||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code);
|
ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code);
|
||||||
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
goto error; // NOLINT(cppcoreguidelines-avoid-goto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acknowledge Update end OK - 1 byte
|
// Acknowledge Update end OK - 1 byte
|
||||||
buf[0] = ota::OTA_RESPONSE_UPDATE_END_OK;
|
buf[0] = ota_base::OTA_RESPONSE_UPDATE_END_OK;
|
||||||
this->writeall_(buf, 1);
|
this->writeall_(buf, 1);
|
||||||
|
|
||||||
// Read ACK
|
// Read ACK
|
||||||
if (!this->readall_(buf, 1) || buf[0] != ota::OTA_RESPONSE_OK) {
|
if (!this->readall_(buf, 1) || buf[0] != ota_base::OTA_RESPONSE_OK) {
|
||||||
ESP_LOGW(TAG, "Reading back acknowledgement failed");
|
ESP_LOGW(TAG, "Reading back acknowledgement failed");
|
||||||
// do not go to error, this is not fatal
|
// do not go to error, this is not fatal
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ void ESPHomeOTAComponent::handle_() {
|
|||||||
ESP_LOGI(TAG, "Update complete");
|
ESP_LOGI(TAG, "Update complete");
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, 0);
|
this->state_callback_.call(ota_base::OTA_COMPLETED, 100.0f, 0);
|
||||||
#endif
|
#endif
|
||||||
delay(100); // NOLINT
|
delay(100); // NOLINT
|
||||||
App.safe_reboot();
|
App.safe_reboot();
|
||||||
@@ -355,7 +355,7 @@ error:
|
|||||||
|
|
||||||
this->status_momentary_error("onerror", 5000);
|
this->status_momentary_error("onerror", 5000);
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
|
this->state_callback_.call(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/preferences.h"
|
#include "esphome/core/preferences.h"
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#include "esphome/components/socket/socket.h"
|
#include "esphome/components/socket/socket.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
/// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA.
|
/// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA.
|
||||||
class ESPHomeOTAComponent : public ota::OTAComponent {
|
class ESPHomeOTAComponent : public ota_base::OTAComponent {
|
||||||
public:
|
public:
|
||||||
#ifdef USE_OTA_PASSWORD
|
#ifdef USE_OTA_PASSWORD
|
||||||
void set_auth_password(const std::string &password) { password_ = password; }
|
void set_auth_password(const std::string &password) { password_ = password; }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
|
from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME
|
from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME
|
||||||
from esphome.core import coroutine_with_priority
|
from esphome.core import coroutine_with_priority
|
||||||
@@ -15,6 +15,9 @@ DEPENDENCIES = ["network", "http_request"]
|
|||||||
CONF_MD5 = "md5"
|
CONF_MD5 = "md5"
|
||||||
CONF_MD5_URL = "md5_url"
|
CONF_MD5_URL = "md5_url"
|
||||||
|
|
||||||
|
ota_base_ns = cg.esphome_ns.namespace("ota_base")
|
||||||
|
OTAComponent = ota_base_ns.class_("OTAComponent", cg.Component)
|
||||||
|
|
||||||
OtaHttpRequestComponent = http_request_ns.class_(
|
OtaHttpRequestComponent = http_request_ns.class_(
|
||||||
"OtaHttpRequestComponent", OTAComponent
|
"OtaHttpRequestComponent", OTAComponent
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
#include "esphome/components/md5/md5.h"
|
#include "esphome/components/md5/md5.h"
|
||||||
#include "esphome/components/watchdog/watchdog.h"
|
#include "esphome/components/watchdog/watchdog.h"
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_esp32.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_esp32.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_esp8266.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_esp8266.h"
|
||||||
#include "esphome/components/ota/ota_backend_arduino_rp2040.h"
|
#include "esphome/components/ota_base/ota_backend_arduino_rp2040.h"
|
||||||
#include "esphome/components/ota/ota_backend_esp_idf.h"
|
#include "esphome/components/ota_base/ota_backend_esp_idf.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace http_request {
|
namespace http_request {
|
||||||
@@ -19,7 +19,7 @@ static const char *const TAG = "http_request.ota";
|
|||||||
|
|
||||||
void OtaHttpRequestComponent::setup() {
|
void OtaHttpRequestComponent::setup() {
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
ota::register_ota_platform(this);
|
ota_base::register_ota_platform(this);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,15 +50,15 @@ void OtaHttpRequestComponent::flash() {
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Starting update");
|
ESP_LOGI(TAG, "Starting update");
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0);
|
this->state_callback_.call(ota_base::OTA_STARTED, 0.0f, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto ota_status = this->do_ota_();
|
auto ota_status = this->do_ota_();
|
||||||
|
|
||||||
switch (ota_status) {
|
switch (ota_status) {
|
||||||
case ota::OTA_RESPONSE_OK:
|
case ota_base::OTA_RESPONSE_OK:
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, ota_status);
|
this->state_callback_.call(ota_base::OTA_COMPLETED, 100.0f, ota_status);
|
||||||
#endif
|
#endif
|
||||||
delay(10);
|
delay(10);
|
||||||
App.safe_reboot();
|
App.safe_reboot();
|
||||||
@@ -66,7 +66,7 @@ void OtaHttpRequestComponent::flash() {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_ERROR, 0.0f, ota_status);
|
this->state_callback_.call(ota_base::OTA_ERROR, 0.0f, ota_status);
|
||||||
#endif
|
#endif
|
||||||
this->md5_computed_.clear(); // will be reset at next attempt
|
this->md5_computed_.clear(); // will be reset at next attempt
|
||||||
this->md5_expected_.clear(); // will be reset at next attempt
|
this->md5_expected_.clear(); // will be reset at next attempt
|
||||||
@@ -74,7 +74,7 @@ void OtaHttpRequestComponent::flash() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtaHttpRequestComponent::cleanup_(std::unique_ptr<ota::OTABackend> backend,
|
void OtaHttpRequestComponent::cleanup_(std::unique_ptr<ota_base::OTABackend> backend,
|
||||||
const std::shared_ptr<HttpContainer> &container) {
|
const std::shared_ptr<HttpContainer> &container) {
|
||||||
if (this->update_started_) {
|
if (this->update_started_) {
|
||||||
ESP_LOGV(TAG, "Aborting OTA backend");
|
ESP_LOGV(TAG, "Aborting OTA backend");
|
||||||
@@ -115,9 +115,9 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
|||||||
ESP_LOGV(TAG, "MD5Digest initialized");
|
ESP_LOGV(TAG, "MD5Digest initialized");
|
||||||
|
|
||||||
ESP_LOGV(TAG, "OTA backend begin");
|
ESP_LOGV(TAG, "OTA backend begin");
|
||||||
auto backend = ota::make_ota_backend();
|
auto backend = ota_base::make_ota_backend();
|
||||||
auto error_code = backend->begin(container->content_length);
|
auto error_code = backend->begin(container->content_length);
|
||||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
ESP_LOGW(TAG, "backend->begin error: %d", error_code);
|
ESP_LOGW(TAG, "backend->begin error: %d", error_code);
|
||||||
this->cleanup_(std::move(backend), container);
|
this->cleanup_(std::move(backend), container);
|
||||||
return error_code;
|
return error_code;
|
||||||
@@ -144,7 +144,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
|||||||
// write bytes to OTA backend
|
// write bytes to OTA backend
|
||||||
this->update_started_ = true;
|
this->update_started_ = true;
|
||||||
error_code = backend->write(buf, bufsize);
|
error_code = backend->write(buf, bufsize);
|
||||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
// error code explanation available at
|
// error code explanation available at
|
||||||
// https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h
|
// https://github.com/esphome/esphome/blob/dev/esphome/components/ota/ota_backend.h
|
||||||
ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code,
|
ESP_LOGE(TAG, "Error code (%02X) writing binary data to flash at offset %d and size %d", error_code,
|
||||||
@@ -160,7 +160,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
|||||||
float percentage = container->get_bytes_read() * 100.0f / container->content_length;
|
float percentage = container->get_bytes_read() * 100.0f / container->content_length;
|
||||||
ESP_LOGD(TAG, "Progress: %0.1f%%", percentage);
|
ESP_LOGD(TAG, "Progress: %0.1f%%", percentage);
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0);
|
this->state_callback_.call(ota_base::OTA_IN_PROGRESS, percentage, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // while
|
} // while
|
||||||
@@ -174,7 +174,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
|||||||
if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) {
|
if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) {
|
||||||
ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str());
|
ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str());
|
||||||
this->cleanup_(std::move(backend), container);
|
this->cleanup_(std::move(backend), container);
|
||||||
return ota::OTA_RESPONSE_ERROR_MD5_MISMATCH;
|
return ota_base::OTA_RESPONSE_ERROR_MD5_MISMATCH;
|
||||||
} else {
|
} else {
|
||||||
backend->set_update_md5(md5_receive_str.get());
|
backend->set_update_md5(md5_receive_str.get());
|
||||||
}
|
}
|
||||||
@@ -187,14 +187,14 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
|||||||
delay(100); // NOLINT
|
delay(100); // NOLINT
|
||||||
|
|
||||||
error_code = backend->end();
|
error_code = backend->end();
|
||||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code);
|
ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code);
|
||||||
this->cleanup_(std::move(backend), container);
|
this->cleanup_(std::move(backend), container);
|
||||||
return error_code;
|
return error_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Update complete");
|
ESP_LOGI(TAG, "Update complete");
|
||||||
return ota::OTA_RESPONSE_OK;
|
return ota_base::OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) {
|
std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
@@ -22,7 +22,7 @@ enum OtaHttpRequestError : uint8_t {
|
|||||||
OTA_CONNECTION_ERROR = 0x12,
|
OTA_CONNECTION_ERROR = 0x12,
|
||||||
};
|
};
|
||||||
|
|
||||||
class OtaHttpRequestComponent : public ota::OTAComponent, public Parented<HttpRequestComponent> {
|
class OtaHttpRequestComponent : public ota_base::OTAComponent, public Parented<HttpRequestComponent> {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
@@ -40,7 +40,7 @@ class OtaHttpRequestComponent : public ota::OTAComponent, public Parented<HttpRe
|
|||||||
void flash();
|
void flash();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleanup_(std::unique_ptr<ota::OTABackend> backend, const std::shared_ptr<HttpContainer> &container);
|
void cleanup_(std::unique_ptr<ota_base::OTABackend> backend, const std::shared_ptr<HttpContainer> &container);
|
||||||
uint8_t do_ota_();
|
uint8_t do_ota_();
|
||||||
std::string get_url_with_auth_(const std::string &url);
|
std::string get_url_with_auth_(const std::string &url);
|
||||||
bool http_get_md5_();
|
bool http_get_md5_();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "esphome/components/json/json_util.h"
|
#include "esphome/components/json/json_util.h"
|
||||||
#include "esphome/components/network/util.h"
|
#include "esphome/components/network/util.h"
|
||||||
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace http_request {
|
namespace http_request {
|
||||||
@@ -21,13 +22,13 @@ static const char *const TAG = "http_request.update";
|
|||||||
static const size_t MAX_READ_SIZE = 256;
|
static const size_t MAX_READ_SIZE = 256;
|
||||||
|
|
||||||
void HttpRequestUpdate::setup() {
|
void HttpRequestUpdate::setup() {
|
||||||
this->ota_parent_->add_on_state_callback([this](ota::OTAState state, float progress, uint8_t err) {
|
this->ota_parent_->add_on_state_callback([this](ota_base::OTAState state, float progress, uint8_t err) {
|
||||||
if (state == ota::OTAState::OTA_IN_PROGRESS) {
|
if (state == ota_base::OTAState::OTA_IN_PROGRESS) {
|
||||||
this->state_ = update::UPDATE_STATE_INSTALLING;
|
this->state_ = update::UPDATE_STATE_INSTALLING;
|
||||||
this->update_info_.has_progress = true;
|
this->update_info_.has_progress = true;
|
||||||
this->update_info_.progress = progress;
|
this->update_info_.progress = progress;
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
} else if (state == ota::OTAState::OTA_ABORT || state == ota::OTAState::OTA_ERROR) {
|
} else if (state == ota_base::OTAState::OTA_ABORT || state == ota_base::OTAState::OTA_ERROR) {
|
||||||
this->state_ = update::UPDATE_STATE_AVAILABLE;
|
this->state_ = update::UPDATE_STATE_AVAILABLE;
|
||||||
this->status_set_error("Failed to install firmware");
|
this->status_set_error("Failed to install firmware");
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "esphome/components/audio/audio_transfer_buffer.h"
|
#include "esphome/components/audio/audio_transfer_buffer.h"
|
||||||
|
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -121,11 +121,11 @@ void MicroWakeWord::setup() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
ota::get_global_ota_callback()->add_on_state_callback(
|
ota_base::get_global_ota_callback()->add_on_state_callback(
|
||||||
[this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) {
|
[this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) {
|
||||||
if (state == ota::OTA_STARTED) {
|
if (state == ota_base::OTA_STARTED) {
|
||||||
this->suspend_task_();
|
this->suspend_task_();
|
||||||
} else if (state == ota::OTA_ERROR) {
|
} else if (state == ota_base::OTA_ERROR) {
|
||||||
this->resume_task_();
|
this->resume_task_();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ from esphome.const import (
|
|||||||
CONF_PLATFORM,
|
CONF_PLATFORM,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, coroutine_with_priority
|
from esphome.core import coroutine_with_priority
|
||||||
|
|
||||||
|
from ..ota_base import OTAState
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
AUTO_LOAD = ["md5", "safe_mode"]
|
AUTO_LOAD = ["safe_mode", "ota_base"]
|
||||||
|
|
||||||
IS_PLATFORM_COMPONENT = True
|
IS_PLATFORM_COMPONENT = True
|
||||||
|
|
||||||
@@ -23,8 +25,6 @@ CONF_ON_STATE_CHANGE = "on_state_change"
|
|||||||
|
|
||||||
|
|
||||||
ota_ns = cg.esphome_ns.namespace("ota")
|
ota_ns = cg.esphome_ns.namespace("ota")
|
||||||
OTAComponent = ota_ns.class_("OTAComponent", cg.Component)
|
|
||||||
OTAState = ota_ns.enum("OTAState")
|
|
||||||
OTAAbortTrigger = ota_ns.class_("OTAAbortTrigger", automation.Trigger.template())
|
OTAAbortTrigger = ota_ns.class_("OTAAbortTrigger", automation.Trigger.template())
|
||||||
OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template())
|
OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template())
|
||||||
OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template())
|
OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template())
|
||||||
@@ -84,12 +84,6 @@ BASE_OTA_SCHEMA = cv.Schema(
|
|||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
cg.add_define("USE_OTA")
|
cg.add_define("USE_OTA")
|
||||||
|
|
||||||
if CORE.is_esp32 and CORE.using_arduino:
|
|
||||||
cg.add_library("Update", None)
|
|
||||||
|
|
||||||
if CORE.is_rp2040 and CORE.using_arduino:
|
|
||||||
cg.add_library("Updater", None)
|
|
||||||
|
|
||||||
|
|
||||||
async def ota_to_code(var, config):
|
async def ota_to_code(var, config):
|
||||||
await cg.past_safe_mode()
|
await cg.past_safe_mode()
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
#include "ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota {
|
||||||
|
|
||||||
|
// Import types from ota_base for the automation triggers
|
||||||
|
using ota_base::OTAComponent;
|
||||||
|
using ota_base::OTAState;
|
||||||
|
|
||||||
class OTAStateChangeTrigger : public Trigger<OTAState> {
|
class OTAStateChangeTrigger : public Trigger<OTAState> {
|
||||||
public:
|
public:
|
||||||
explicit OTAStateChangeTrigger(OTAComponent *parent) {
|
explicit OTAStateChangeTrigger(OTAComponent *parent) {
|
||||||
@@ -22,7 +26,7 @@ class OTAStartTrigger : public Trigger<> {
|
|||||||
public:
|
public:
|
||||||
explicit OTAStartTrigger(OTAComponent *parent) {
|
explicit OTAStartTrigger(OTAComponent *parent) {
|
||||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||||
if (state == OTA_STARTED && !parent->is_failed()) {
|
if (state == ota_base::OTA_STARTED && !parent->is_failed()) {
|
||||||
trigger();
|
trigger();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -33,7 +37,7 @@ class OTAProgressTrigger : public Trigger<float> {
|
|||||||
public:
|
public:
|
||||||
explicit OTAProgressTrigger(OTAComponent *parent) {
|
explicit OTAProgressTrigger(OTAComponent *parent) {
|
||||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||||
if (state == OTA_IN_PROGRESS && !parent->is_failed()) {
|
if (state == ota_base::OTA_IN_PROGRESS && !parent->is_failed()) {
|
||||||
trigger(progress);
|
trigger(progress);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -44,7 +48,7 @@ class OTAEndTrigger : public Trigger<> {
|
|||||||
public:
|
public:
|
||||||
explicit OTAEndTrigger(OTAComponent *parent) {
|
explicit OTAEndTrigger(OTAComponent *parent) {
|
||||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||||
if (state == OTA_COMPLETED && !parent->is_failed()) {
|
if (state == ota_base::OTA_COMPLETED && !parent->is_failed()) {
|
||||||
trigger();
|
trigger();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -55,7 +59,7 @@ class OTAAbortTrigger : public Trigger<> {
|
|||||||
public:
|
public:
|
||||||
explicit OTAAbortTrigger(OTAComponent *parent) {
|
explicit OTAAbortTrigger(OTAComponent *parent) {
|
||||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||||
if (state == OTA_ABORT && !parent->is_failed()) {
|
if (state == ota_base::OTA_ABORT && !parent->is_failed()) {
|
||||||
trigger();
|
trigger();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -66,7 +70,7 @@ class OTAErrorTrigger : public Trigger<uint8_t> {
|
|||||||
public:
|
public:
|
||||||
explicit OTAErrorTrigger(OTAComponent *parent) {
|
explicit OTAErrorTrigger(OTAComponent *parent) {
|
||||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||||
if (state == OTA_ERROR && !parent->is_failed()) {
|
if (state == ota_base::OTA_ERROR && !parent->is_failed()) {
|
||||||
trigger(error);
|
trigger(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
23
esphome/components/ota_base/__init__.py
Normal file
23
esphome/components/ota_base/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
|
||||||
|
CODEOWNERS = ["@esphome/core"]
|
||||||
|
AUTO_LOAD = ["md5"]
|
||||||
|
|
||||||
|
ota_base_ns = cg.esphome_ns.namespace("ota_base")
|
||||||
|
OTAComponent = ota_base_ns.class_("OTAComponent", cg.Component)
|
||||||
|
OTAState = ota_base_ns.enum("OTAState")
|
||||||
|
|
||||||
|
|
||||||
|
@coroutine_with_priority(52.0)
|
||||||
|
async def to_code(config):
|
||||||
|
# Note: USE_OTA_STATE_CALLBACK is not defined here
|
||||||
|
# Components that need OTA callbacks (like esp32_ble_tracker, speaker, etc.)
|
||||||
|
# define USE_OTA_STATE_CALLBACK themselves in their own __init__.py files
|
||||||
|
# This ensures the callback functionality is only compiled when actually needed
|
||||||
|
|
||||||
|
if CORE.is_esp32 and CORE.using_arduino:
|
||||||
|
cg.add_library("Update", None)
|
||||||
|
|
||||||
|
if CORE.is_rp2040 and CORE.using_arduino:
|
||||||
|
cg.add_library("Updater", None)
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "ota_backend.h"
|
#include "ota_backend.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
|
// The make_ota_backend() implementation is provided by each platform-specific backend
|
||||||
|
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
OTAGlobalCallback *global_ota_callback{nullptr}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
OTAGlobalCallback *global_ota_callback{nullptr}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
@@ -16,5 +18,5 @@ OTAGlobalCallback *get_global_ota_callback() {
|
|||||||
void register_ota_platform(OTAComponent *ota_caller) { get_global_ota_callback()->register_ota(ota_caller); }
|
void register_ota_platform(OTAComponent *ota_caller) { get_global_ota_callback()->register_ota(ota_caller); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
enum OTAResponseTypes {
|
enum OTAResponseTypes {
|
||||||
OTA_RESPONSE_OK = 0x00,
|
OTA_RESPONSE_OK = 0x00,
|
||||||
@@ -59,15 +59,38 @@ class OTABackend {
|
|||||||
virtual bool supports_compression() = 0;
|
virtual bool supports_compression() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<OTABackend> make_ota_backend();
|
||||||
|
|
||||||
class OTAComponent : public Component {
|
class OTAComponent : public Component {
|
||||||
#ifdef USE_OTA_STATE_CALLBACK
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
public:
|
public:
|
||||||
void add_on_state_callback(std::function<void(ota::OTAState, float, uint8_t)> &&callback) {
|
void add_on_state_callback(std::function<void(OTAState, float, uint8_t)> &&callback) {
|
||||||
this->state_callback_.add(std::move(callback));
|
this->state_callback_.add(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CallbackManager<void(ota::OTAState, float, uint8_t)> state_callback_{};
|
/** Extended callback manager with deferred call support.
|
||||||
|
*
|
||||||
|
* This adds a call_deferred() method for thread-safe execution from other tasks.
|
||||||
|
*/
|
||||||
|
class StateCallbackManager : public CallbackManager<void(OTAState, float, uint8_t)> {
|
||||||
|
public:
|
||||||
|
StateCallbackManager(OTAComponent *component) : component_(component) {}
|
||||||
|
|
||||||
|
/** Call callbacks with deferral to main loop (for thread safety).
|
||||||
|
*
|
||||||
|
* This should be used by OTA implementations that run in separate tasks
|
||||||
|
* (like web_server OTA) to ensure callbacks execute in the main loop.
|
||||||
|
*/
|
||||||
|
void call_deferred(OTAState state, float progress, uint8_t error) {
|
||||||
|
component_->defer([this, state, progress, error]() { this->call(state, progress, error); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
OTAComponent *component_;
|
||||||
|
};
|
||||||
|
|
||||||
|
StateCallbackManager state_callback_{this};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,8 +112,12 @@ class OTAGlobalCallback {
|
|||||||
|
|
||||||
OTAGlobalCallback *get_global_ota_callback();
|
OTAGlobalCallback *get_global_ota_callback();
|
||||||
void register_ota_platform(OTAComponent *ota_caller);
|
void register_ota_platform(OTAComponent *ota_caller);
|
||||||
#endif
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend();
|
|
||||||
|
|
||||||
} // namespace ota
|
// OTA implementations should use:
|
||||||
|
// - state_callback_.call() when already in main loop (e.g., esphome OTA)
|
||||||
|
// - state_callback_.call_deferred() when in separate task (e.g., web_server OTA)
|
||||||
|
// This ensures proper callback execution in all contexts.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
@@ -8,13 +8,18 @@
|
|||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
static const char *const TAG = "ota.arduino_esp32";
|
static const char *const TAG = "ota.arduino_esp32";
|
||||||
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP32OTABackend>(); }
|
std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoESP32OTABackend>(); }
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
|
OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
|
||||||
|
// Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
|
||||||
|
// where the exact firmware size is unknown due to multipart encoding
|
||||||
|
if (image_size == 0) {
|
||||||
|
image_size = UPDATE_SIZE_UNKNOWN;
|
||||||
|
}
|
||||||
bool ret = Update.begin(image_size, U_FLASH);
|
bool ret = Update.begin(image_size, U_FLASH);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
@@ -29,7 +34,10 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
|
|||||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
|
void ArduinoESP32OTABackend::set_update_md5(const char *md5) {
|
||||||
|
Update.setMD5(md5);
|
||||||
|
this->md5_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
|
OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
|
||||||
size_t written = Update.write(data, len);
|
size_t written = Update.write(data, len);
|
||||||
@@ -44,7 +52,9 @@ OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP32OTABackend::end() {
|
OTAResponseTypes ArduinoESP32OTABackend::end() {
|
||||||
if (Update.end()) {
|
// Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
|
||||||
|
// This matches the behavior of the old web_server OTA implementation
|
||||||
|
if (Update.end(!this->md5_set_)) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +66,7 @@ OTAResponseTypes ArduinoESP32OTABackend::end() {
|
|||||||
|
|
||||||
void ArduinoESP32OTABackend::abort() { Update.abort(); }
|
void ArduinoESP32OTABackend::abort() { Update.abort(); }
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_ESP32_FRAMEWORK_ARDUINO
|
#endif // USE_ESP32_FRAMEWORK_ARDUINO
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
class ArduinoESP32OTABackend : public OTABackend {
|
class ArduinoESP32OTABackend : public OTABackend {
|
||||||
public:
|
public:
|
||||||
@@ -16,9 +16,12 @@ class ArduinoESP32OTABackend : public OTABackend {
|
|||||||
OTAResponseTypes end() override;
|
OTAResponseTypes end() override;
|
||||||
void abort() override;
|
void abort() override;
|
||||||
bool supports_compression() override { return false; }
|
bool supports_compression() override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool md5_set_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_ESP32_FRAMEWORK_ARDUINO
|
#endif // USE_ESP32_FRAMEWORK_ARDUINO
|
||||||
@@ -10,13 +10,18 @@
|
|||||||
#include <Updater.h>
|
#include <Updater.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
static const char *const TAG = "ota.arduino_esp8266";
|
static const char *const TAG = "ota.arduino_esp8266";
|
||||||
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP8266OTABackend>(); }
|
std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoESP8266OTABackend>(); }
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
||||||
|
// Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
|
||||||
|
if (image_size == 0) {
|
||||||
|
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||||
|
image_size = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
}
|
||||||
bool ret = Update.begin(image_size, U_FLASH);
|
bool ret = Update.begin(image_size, U_FLASH);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
esp8266::preferences_prevent_write(true);
|
esp8266::preferences_prevent_write(true);
|
||||||
@@ -38,7 +43,10 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
|||||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
|
void ArduinoESP8266OTABackend::set_update_md5(const char *md5) {
|
||||||
|
Update.setMD5(md5);
|
||||||
|
this->md5_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
|
OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
|
||||||
size_t written = Update.write(data, len);
|
size_t written = Update.write(data, len);
|
||||||
@@ -53,13 +61,19 @@ OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoESP8266OTABackend::end() {
|
OTAResponseTypes ArduinoESP8266OTABackend::end() {
|
||||||
if (Update.end()) {
|
// Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
|
||||||
|
// This matches the behavior of the old web_server OTA implementation
|
||||||
|
bool success = Update.end(!this->md5_set_);
|
||||||
|
|
||||||
|
// On ESP8266, Update.end() might return false even with error code 0
|
||||||
|
// Check the actual error code to determine success
|
||||||
|
uint8_t error = Update.getError();
|
||||||
|
|
||||||
|
if (success || error == UPDATE_ERROR_OK) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t error = Update.getError();
|
|
||||||
ESP_LOGE(TAG, "End error: %d", error);
|
ESP_LOGE(TAG, "End error: %d", error);
|
||||||
|
|
||||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +82,7 @@ void ArduinoESP8266OTABackend::abort() {
|
|||||||
esp8266::preferences_prevent_write(false);
|
esp8266::preferences_prevent_write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "esphome/core/macros.h"
|
#include "esphome/core/macros.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
class ArduinoESP8266OTABackend : public OTABackend {
|
class ArduinoESP8266OTABackend : public OTABackend {
|
||||||
public:
|
public:
|
||||||
@@ -21,9 +21,12 @@ class ArduinoESP8266OTABackend : public OTABackend {
|
|||||||
#else
|
#else
|
||||||
bool supports_compression() override { return false; }
|
bool supports_compression() override { return false; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool md5_set_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -8,13 +8,18 @@
|
|||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
static const char *const TAG = "ota.arduino_libretiny";
|
static const char *const TAG = "ota.arduino_libretiny";
|
||||||
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoLibreTinyOTABackend>(); }
|
std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoLibreTinyOTABackend>(); }
|
||||||
|
|
||||||
OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
|
OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
|
||||||
|
// Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
|
||||||
|
// where the exact firmware size is unknown due to multipart encoding
|
||||||
|
if (image_size == 0) {
|
||||||
|
image_size = UPDATE_SIZE_UNKNOWN;
|
||||||
|
}
|
||||||
bool ret = Update.begin(image_size, U_FLASH);
|
bool ret = Update.begin(image_size, U_FLASH);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
@@ -29,7 +34,10 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
|
|||||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
|
void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) {
|
||||||
|
Update.setMD5(md5);
|
||||||
|
this->md5_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
|
OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
|
||||||
size_t written = Update.write(data, len);
|
size_t written = Update.write(data, len);
|
||||||
@@ -44,7 +52,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoLibreTinyOTABackend::end() {
|
OTAResponseTypes ArduinoLibreTinyOTABackend::end() {
|
||||||
if (Update.end()) {
|
// Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
|
||||||
|
// This matches the behavior of the old web_server OTA implementation
|
||||||
|
if (Update.end(!this->md5_set_)) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +66,7 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::end() {
|
|||||||
|
|
||||||
void ArduinoLibreTinyOTABackend::abort() { Update.abort(); }
|
void ArduinoLibreTinyOTABackend::abort() { Update.abort(); }
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_LIBRETINY
|
#endif // USE_LIBRETINY
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
class ArduinoLibreTinyOTABackend : public OTABackend {
|
class ArduinoLibreTinyOTABackend : public OTABackend {
|
||||||
public:
|
public:
|
||||||
@@ -15,9 +15,12 @@ class ArduinoLibreTinyOTABackend : public OTABackend {
|
|||||||
OTAResponseTypes end() override;
|
OTAResponseTypes end() override;
|
||||||
void abort() override;
|
void abort() override;
|
||||||
bool supports_compression() override { return false; }
|
bool supports_compression() override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool md5_set_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_LIBRETINY
|
#endif // USE_LIBRETINY
|
||||||
@@ -10,13 +10,24 @@
|
|||||||
#include <Updater.h>
|
#include <Updater.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
static const char *const TAG = "ota.arduino_rp2040";
|
static const char *const TAG = "ota.arduino_rp2040";
|
||||||
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoRP2040OTABackend>(); }
|
std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<ArduinoRP2040OTABackend>(); }
|
||||||
|
|
||||||
OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
||||||
|
// Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
|
||||||
|
if (image_size == 0) {
|
||||||
|
// Similar to ESP8266, calculate available space from flash layout
|
||||||
|
extern uint8_t _FS_start;
|
||||||
|
extern uint8_t _FS_end;
|
||||||
|
// Calculate the size of the filesystem area which will be used for OTA
|
||||||
|
size_t fs_size = &_FS_end - &_FS_start;
|
||||||
|
// Reserve some space for filesystem overhead
|
||||||
|
image_size = (fs_size - 0x1000) & 0xFFFFF000;
|
||||||
|
ESP_LOGD(TAG, "OTA size unknown, using filesystem size: %u bytes", image_size);
|
||||||
|
}
|
||||||
bool ret = Update.begin(image_size, U_FLASH);
|
bool ret = Update.begin(image_size, U_FLASH);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
rp2040::preferences_prevent_write(true);
|
rp2040::preferences_prevent_write(true);
|
||||||
@@ -38,7 +49,10 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
|||||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
|
void ArduinoRP2040OTABackend::set_update_md5(const char *md5) {
|
||||||
|
Update.setMD5(md5);
|
||||||
|
this->md5_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
|
OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
|
||||||
size_t written = Update.write(data, len);
|
size_t written = Update.write(data, len);
|
||||||
@@ -53,7 +67,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OTAResponseTypes ArduinoRP2040OTABackend::end() {
|
OTAResponseTypes ArduinoRP2040OTABackend::end() {
|
||||||
if (Update.end()) {
|
// Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
|
||||||
|
// This matches the behavior of the old web_server OTA implementation
|
||||||
|
if (Update.end(!this->md5_set_)) {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +84,7 @@ void ArduinoRP2040OTABackend::abort() {
|
|||||||
rp2040::preferences_prevent_write(false);
|
rp2040::preferences_prevent_write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_RP2040
|
#endif // USE_RP2040
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "esphome/core/macros.h"
|
#include "esphome/core/macros.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
class ArduinoRP2040OTABackend : public OTABackend {
|
class ArduinoRP2040OTABackend : public OTABackend {
|
||||||
public:
|
public:
|
||||||
@@ -17,9 +17,12 @@ class ArduinoRP2040OTABackend : public OTABackend {
|
|||||||
OTAResponseTypes end() override;
|
OTAResponseTypes end() override;
|
||||||
void abort() override;
|
void abort() override;
|
||||||
bool supports_compression() override { return false; }
|
bool supports_compression() override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool md5_set_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_RP2040
|
#endif // USE_RP2040
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
#include <spi_flash_mmap.h>
|
#include <spi_flash_mmap.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::IDFOTABackend>(); }
|
std::unique_ptr<OTABackend> make_ota_backend() { return make_unique<IDFOTABackend>(); }
|
||||||
|
|
||||||
OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
|
OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
|
||||||
this->partition_ = esp_ota_get_next_update_partition(nullptr);
|
this->partition_ = esp_ota_get_next_update_partition(nullptr);
|
||||||
@@ -56,7 +56,10 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
|
|||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDFOTABackend::set_update_md5(const char *expected_md5) { memcpy(this->expected_bin_md5_, expected_md5, 32); }
|
void IDFOTABackend::set_update_md5(const char *expected_md5) {
|
||||||
|
memcpy(this->expected_bin_md5_, expected_md5, 32);
|
||||||
|
this->md5_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
|
OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
|
||||||
esp_err_t err = esp_ota_write(this->update_handle_, data, len);
|
esp_err_t err = esp_ota_write(this->update_handle_, data, len);
|
||||||
@@ -73,10 +76,12 @@ OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OTAResponseTypes IDFOTABackend::end() {
|
OTAResponseTypes IDFOTABackend::end() {
|
||||||
this->md5_.calculate();
|
if (this->md5_set_) {
|
||||||
if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
|
this->md5_.calculate();
|
||||||
this->abort();
|
if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
|
||||||
return OTA_RESPONSE_ERROR_MD5_MISMATCH;
|
this->abort();
|
||||||
|
return OTA_RESPONSE_ERROR_MD5_MISMATCH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
esp_err_t err = esp_ota_end(this->update_handle_);
|
esp_err_t err = esp_ota_end(this->update_handle_);
|
||||||
this->update_handle_ = 0;
|
this->update_handle_ = 0;
|
||||||
@@ -100,6 +105,6 @@ void IDFOTABackend::abort() {
|
|||||||
this->update_handle_ = 0;
|
this->update_handle_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
#endif
|
#endif
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ota {
|
namespace ota_base {
|
||||||
|
|
||||||
class IDFOTABackend : public OTABackend {
|
class IDFOTABackend : public OTABackend {
|
||||||
public:
|
public:
|
||||||
@@ -24,8 +24,9 @@ class IDFOTABackend : public OTABackend {
|
|||||||
const esp_partition_t *partition_;
|
const esp_partition_t *partition_;
|
||||||
md5::MD5Digest md5_{};
|
md5::MD5Digest md5_{};
|
||||||
char expected_bin_md5_[32];
|
char expected_bin_md5_[32];
|
||||||
|
bool md5_set_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota_base
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
#endif
|
#endif
|
||||||
26
esphome/components/runtime_stats/__init__.py
Normal file
26
esphome/components/runtime_stats/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""
|
||||||
|
Runtime statistics component for ESPHome.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
|
||||||
|
DEPENDENCIES = []
|
||||||
|
|
||||||
|
CONF_ENABLED = "enabled"
|
||||||
|
CONF_LOG_INTERVAL = "log_interval"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_ENABLED, default=True): cv.boolean,
|
||||||
|
cv.Optional(
|
||||||
|
CONF_LOG_INTERVAL, default=60000
|
||||||
|
): cv.positive_time_period_milliseconds,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
"""Generate code for the runtime statistics component."""
|
||||||
|
cg.add(cg.App.set_runtime_stats_enabled(config[CONF_ENABLED]))
|
||||||
|
cg.add(cg.App.set_runtime_stats_log_interval(config[CONF_LOG_INTERVAL]))
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "esphome/components/audio/audio.h"
|
#include "esphome/components/audio/audio.h"
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
#include "esphome/components/ota/ota_backend.h"
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -67,16 +67,16 @@ void SpeakerMediaPlayer::setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_OTA
|
#ifdef USE_OTA
|
||||||
ota::get_global_ota_callback()->add_on_state_callback(
|
ota_base::get_global_ota_callback()->add_on_state_callback(
|
||||||
[this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) {
|
[this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) {
|
||||||
if (state == ota::OTA_STARTED) {
|
if (state == ota_base::OTA_STARTED) {
|
||||||
if (this->media_pipeline_ != nullptr) {
|
if (this->media_pipeline_ != nullptr) {
|
||||||
this->media_pipeline_->suspend_tasks();
|
this->media_pipeline_->suspend_tasks();
|
||||||
}
|
}
|
||||||
if (this->announcement_pipeline_ != nullptr) {
|
if (this->announcement_pipeline_ != nullptr) {
|
||||||
this->announcement_pipeline_->suspend_tasks();
|
this->announcement_pipeline_->suspend_tasks();
|
||||||
}
|
}
|
||||||
} else if (state == ota::OTA_ERROR) {
|
} else if (state == ota_base::OTA_ERROR) {
|
||||||
if (this->media_pipeline_ != nullptr) {
|
if (this->media_pipeline_ != nullptr) {
|
||||||
this->media_pipeline_->resume_tasks();
|
this->media_pipeline_->resume_tasks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from esphome.const import (
|
|||||||
from esphome.core import CORE, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
import esphome.final_validate as fv
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
AUTO_LOAD = ["json", "web_server_base"]
|
AUTO_LOAD = ["json", "web_server_base", "ota_base"]
|
||||||
|
|
||||||
CONF_SORTING_GROUP_ID = "sorting_group_id"
|
CONF_SORTING_GROUP_ID = "sorting_group_id"
|
||||||
CONF_SORTING_GROUPS = "sorting_groups"
|
CONF_SORTING_GROUPS = "sorting_groups"
|
||||||
@@ -274,7 +274,7 @@ async def to_code(config):
|
|||||||
cg.add(var.set_allow_ota(config[CONF_OTA]))
|
cg.add(var.set_allow_ota(config[CONF_OTA]))
|
||||||
if config[CONF_OTA]:
|
if config[CONF_OTA]:
|
||||||
# Define USE_WEBSERVER_OTA based only on web_server OTA config
|
# Define USE_WEBSERVER_OTA based only on web_server OTA config
|
||||||
# This allows web server OTA to work without loading the OTA component
|
# Web server OTA now uses ota_base backend for consistency
|
||||||
cg.add_define("USE_WEBSERVER_OTA")
|
cg.add_define("USE_WEBSERVER_OTA")
|
||||||
cg.add(var.set_expose_log(config[CONF_LOG]))
|
cg.add(var.set_expose_log(config[CONF_LOG]))
|
||||||
if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]:
|
if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]:
|
||||||
|
|||||||
@@ -4,19 +4,16 @@
|
|||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_WEBSERVER_OTA
|
||||||
#include <StreamString.h>
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
|
||||||
#include <Update.h>
|
|
||||||
#endif
|
|
||||||
#ifdef USE_ESP8266
|
|
||||||
#include <Updater.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
#ifdef USE_ARDUINO
|
||||||
#include <esp_ota_ops.h>
|
#ifdef USE_ESP8266
|
||||||
#include <esp_task_wdt.h>
|
#include <Updater.h>
|
||||||
|
#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||||
|
#include <Update.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -24,104 +21,6 @@ namespace web_server_base {
|
|||||||
|
|
||||||
static const char *const TAG = "web_server_base";
|
static const char *const TAG = "web_server_base";
|
||||||
|
|
||||||
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
|
||||||
// Minimal OTA backend implementation for web server
|
|
||||||
// This allows OTA updates via web server without requiring the OTA component
|
|
||||||
// TODO: In the future, this should be refactored into a common ota_base component
|
|
||||||
// that both web_server and ota components can depend on, avoiding code duplication
|
|
||||||
// while keeping the components independent. This would allow both ESP-IDF and Arduino
|
|
||||||
// implementations to share the base OTA functionality without requiring the full OTA component.
|
|
||||||
// The IDFWebServerOTABackend class is intentionally designed with the same interface
|
|
||||||
// as OTABackend to make it easy to swap to using OTABackend when the ota component
|
|
||||||
// is split into ota and ota_base in the future.
|
|
||||||
class IDFWebServerOTABackend {
|
|
||||||
public:
|
|
||||||
bool begin() {
|
|
||||||
this->partition_ = esp_ota_get_next_update_partition(nullptr);
|
|
||||||
if (this->partition_ == nullptr) {
|
|
||||||
ESP_LOGE(TAG, "No OTA partition available");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15
|
|
||||||
// The following function takes longer than the default timeout of WDT due to flash erase
|
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
esp_task_wdt_config_t wdtc;
|
|
||||||
wdtc.idle_core_mask = 0;
|
|
||||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
|
|
||||||
wdtc.idle_core_mask |= (1 << 0);
|
|
||||||
#endif
|
|
||||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
|
||||||
wdtc.idle_core_mask |= (1 << 1);
|
|
||||||
#endif
|
|
||||||
wdtc.timeout_ms = 15000;
|
|
||||||
wdtc.trigger_panic = false;
|
|
||||||
esp_task_wdt_reconfigure(&wdtc);
|
|
||||||
#else
|
|
||||||
esp_task_wdt_init(15, false);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
esp_err_t err = esp_ota_begin(this->partition_, 0, &this->update_handle_);
|
|
||||||
|
|
||||||
#if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15
|
|
||||||
// Set the WDT back to the configured timeout
|
|
||||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
|
||||||
wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000;
|
|
||||||
esp_task_wdt_reconfigure(&wdtc);
|
|
||||||
#else
|
|
||||||
esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
esp_ota_abort(this->update_handle_);
|
|
||||||
this->update_handle_ = 0;
|
|
||||||
ESP_LOGE(TAG, "esp_ota_begin failed: %s", esp_err_to_name(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write(uint8_t *data, size_t len) {
|
|
||||||
esp_err_t err = esp_ota_write(this->update_handle_, data, len);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_ota_write failed: %s", esp_err_to_name(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end() {
|
|
||||||
esp_err_t err = esp_ota_end(this->update_handle_);
|
|
||||||
this->update_handle_ = 0;
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_ota_end failed: %s", esp_err_to_name(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = esp_ota_set_boot_partition(this->partition_);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed: %s", esp_err_to_name(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void abort() {
|
|
||||||
if (this->update_handle_ != 0) {
|
|
||||||
esp_ota_abort(this->update_handle_);
|
|
||||||
this->update_handle_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
esp_ota_handle_t update_handle_{0};
|
|
||||||
const esp_partition_t *partition_{nullptr};
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void WebServerBase::add_handler(AsyncWebHandler *handler) {
|
void WebServerBase::add_handler(AsyncWebHandler *handler) {
|
||||||
// remove all handlers
|
// remove all handlers
|
||||||
|
|
||||||
@@ -138,12 +37,21 @@ void WebServerBase::add_handler(AsyncWebHandler *handler) {
|
|||||||
void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) {
|
void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) {
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
if (now - this->last_ota_progress_ > 1000) {
|
if (now - this->last_ota_progress_ > 1000) {
|
||||||
|
float percentage = 0.0f;
|
||||||
if (request->contentLength() != 0) {
|
if (request->contentLength() != 0) {
|
||||||
float percentage = (this->ota_read_length_ * 100.0f) / request->contentLength();
|
// Note: Using contentLength() for progress calculation is technically wrong as it includes
|
||||||
|
// multipart headers/boundaries, but it's only off by a small amount and we don't have
|
||||||
|
// access to the actual firmware size until the upload is complete. This is intentional
|
||||||
|
// as it still gives the user a reasonable progress indication.
|
||||||
|
percentage = (this->ota_read_length_ * 100.0f) / request->contentLength();
|
||||||
ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage);
|
ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_);
|
ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_);
|
||||||
}
|
}
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
// Report progress - use call_deferred since we're in web server task
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_IN_PROGRESS, percentage, 0);
|
||||||
|
#endif
|
||||||
this->last_ota_progress_ = now;
|
this->last_ota_progress_ = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,87 +67,72 @@ void OTARequestHandler::schedule_ota_reboot_() {
|
|||||||
void OTARequestHandler::ota_init_(const char *filename) {
|
void OTARequestHandler::ota_init_(const char *filename) {
|
||||||
ESP_LOGI(TAG, "OTA Update Start: %s", filename);
|
ESP_LOGI(TAG, "OTA Update Start: %s", filename);
|
||||||
this->ota_read_length_ = 0;
|
this->ota_read_length_ = 0;
|
||||||
}
|
this->ota_success_ = false;
|
||||||
|
|
||||||
void report_ota_error() {
|
|
||||||
#ifdef USE_ARDUINO
|
|
||||||
StreamString ss;
|
|
||||||
Update.printError(ss);
|
|
||||||
ESP_LOGW(TAG, "OTA Update failed! Error: %s", ss.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index,
|
void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index,
|
||||||
uint8_t *data, size_t len, bool final) {
|
uint8_t *data, size_t len, bool final) {
|
||||||
#ifdef USE_ARDUINO
|
ota_base::OTAResponseTypes error_code = ota_base::OTA_RESPONSE_OK;
|
||||||
bool success;
|
|
||||||
if (index == 0) {
|
if (index == 0 && !this->ota_backend_) {
|
||||||
|
// Initialize OTA on first call
|
||||||
this->ota_init_(filename.c_str());
|
this->ota_init_(filename.c_str());
|
||||||
|
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
// Notify OTA started - use call_deferred since we're in web server task
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_STARTED, 0.0f, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Platform-specific pre-initialization
|
||||||
|
#ifdef USE_ARDUINO
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
Update.runAsync(true);
|
Update.runAsync(true);
|
||||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
|
||||||
success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY)
|
#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY)
|
||||||
if (Update.isRunning()) {
|
if (Update.isRunning()) {
|
||||||
Update.abort();
|
Update.abort();
|
||||||
}
|
}
|
||||||
success = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH);
|
|
||||||
#endif
|
#endif
|
||||||
if (!success) {
|
|
||||||
report_ota_error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (Update.hasError()) {
|
|
||||||
// don't spam logs with errors if something failed at start
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
success = Update.write(data, len) == len;
|
|
||||||
if (!success) {
|
|
||||||
report_ota_error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->ota_read_length_ += len;
|
|
||||||
this->report_ota_progress_(request);
|
|
||||||
|
|
||||||
if (final) {
|
|
||||||
if (Update.end(true)) {
|
|
||||||
this->schedule_ota_reboot_();
|
|
||||||
} else {
|
|
||||||
report_ota_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // USE_ARDUINO
|
#endif // USE_ARDUINO
|
||||||
|
|
||||||
#ifdef USE_ESP_IDF
|
this->ota_backend_ = ota_base::make_ota_backend();
|
||||||
// ESP-IDF implementation
|
if (!this->ota_backend_) {
|
||||||
if (index == 0 && !this->ota_backend_) {
|
ESP_LOGE(TAG, "Failed to create OTA backend");
|
||||||
// Initialize OTA on first call
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
this->ota_init_(filename.c_str());
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f,
|
||||||
this->ota_success_ = false;
|
static_cast<uint8_t>(ota_base::OTA_RESPONSE_ERROR_UNKNOWN));
|
||||||
|
#endif
|
||||||
auto *backend = new IDFWebServerOTABackend();
|
return;
|
||||||
if (!backend->begin()) {
|
}
|
||||||
ESP_LOGE(TAG, "OTA begin failed");
|
|
||||||
delete backend;
|
// Web server OTA uses multipart uploads where the actual firmware size
|
||||||
|
// is unknown (contentLength includes multipart overhead)
|
||||||
|
// Pass 0 to indicate unknown size
|
||||||
|
error_code = this->ota_backend_->begin(0);
|
||||||
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
|
ESP_LOGE(TAG, "OTA begin failed: %d", error_code);
|
||||||
|
this->ota_backend_.reset();
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->ota_backend_ = backend;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *backend = static_cast<IDFWebServerOTABackend *>(this->ota_backend_);
|
if (!this->ota_backend_) {
|
||||||
if (!backend) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process data
|
// Process data
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (!backend->write(data, len)) {
|
error_code = this->ota_backend_->write(data, len);
|
||||||
ESP_LOGE(TAG, "OTA write failed");
|
if (error_code != ota_base::OTA_RESPONSE_OK) {
|
||||||
backend->abort();
|
ESP_LOGE(TAG, "OTA write failed: %d", error_code);
|
||||||
delete backend;
|
this->ota_backend_->abort();
|
||||||
this->ota_backend_ = nullptr;
|
this->ota_backend_.reset();
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->ota_read_length_ += len;
|
this->ota_read_length_ += len;
|
||||||
@@ -248,40 +141,45 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
|
|||||||
|
|
||||||
// Finalize
|
// Finalize
|
||||||
if (final) {
|
if (final) {
|
||||||
this->ota_success_ = backend->end();
|
ESP_LOGD(TAG, "OTA final chunk: index=%u, len=%u, total_read=%u, contentLength=%u", index, len,
|
||||||
if (this->ota_success_) {
|
this->ota_read_length_, request->contentLength());
|
||||||
|
|
||||||
|
// For Arduino framework, the Update library tracks expected size from firmware header
|
||||||
|
// If we haven't received enough data, calling end() will fail
|
||||||
|
// This can happen if the upload is interrupted or the client disconnects
|
||||||
|
error_code = this->ota_backend_->end();
|
||||||
|
if (error_code == ota_base::OTA_RESPONSE_OK) {
|
||||||
|
this->ota_success_ = true;
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
// Report completion before reboot - use call_deferred since we're in web server task
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_COMPLETED, 100.0f, 0);
|
||||||
|
#endif
|
||||||
this->schedule_ota_reboot_();
|
this->schedule_ota_reboot_();
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "OTA end failed");
|
ESP_LOGE(TAG, "OTA end failed: %d", error_code);
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
this->parent_->state_callback_.call_deferred(ota_base::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
delete backend;
|
this->ota_backend_.reset();
|
||||||
this->ota_backend_ = nullptr;
|
|
||||||
}
|
}
|
||||||
#endif // USE_ESP_IDF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
|
void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
|
||||||
AsyncWebServerResponse *response;
|
AsyncWebServerResponse *response;
|
||||||
#ifdef USE_ARDUINO
|
// Use the ota_success_ flag to determine the actual result
|
||||||
if (!Update.hasError()) {
|
const char *msg = this->ota_success_ ? "Update Successful!" : "Update Failed!";
|
||||||
response = request->beginResponse(200, "text/plain", "Update Successful!");
|
response = request->beginResponse(200, "text/plain", msg);
|
||||||
} else {
|
|
||||||
StreamString ss;
|
|
||||||
ss.print("Update Failed: ");
|
|
||||||
Update.printError(ss);
|
|
||||||
response = request->beginResponse(200, "text/plain", ss);
|
|
||||||
}
|
|
||||||
#endif // USE_ARDUINO
|
|
||||||
#ifdef USE_ESP_IDF
|
|
||||||
// Send response based on the OTA result
|
|
||||||
response = request->beginResponse(200, "text/plain", this->ota_success_ ? "Update Successful!" : "Update Failed!");
|
|
||||||
#endif // USE_ESP_IDF
|
|
||||||
response->addHeader("Connection", "close");
|
response->addHeader("Connection", "close");
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebServerBase::add_ota_handler() {
|
void WebServerBase::add_ota_handler() {
|
||||||
this->add_handler(new OTARequestHandler(this)); // NOLINT
|
this->add_handler(new OTARequestHandler(this)); // NOLINT
|
||||||
|
#ifdef USE_OTA_STATE_CALLBACK
|
||||||
|
// Register with global OTA callback system
|
||||||
|
ota_base::register_ota_platform(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
#include "esphome/components/web_server_idf/web_server_idf.h"
|
#include "esphome/components/web_server_idf/web_server_idf.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER_OTA
|
||||||
|
#include "esphome/components/ota_base/ota_backend.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace web_server_base {
|
namespace web_server_base {
|
||||||
|
|
||||||
@@ -79,7 +83,11 @@ class AuthMiddlewareHandler : public MiddlewareHandler {
|
|||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
#ifdef USE_WEBSERVER_OTA
|
||||||
|
class WebServerBase : public ota_base::OTAComponent {
|
||||||
|
#else
|
||||||
class WebServerBase : public Component {
|
class WebServerBase : public Component {
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
void init() {
|
void init() {
|
||||||
if (this->initialized_) {
|
if (this->initialized_) {
|
||||||
@@ -151,12 +159,10 @@ class OTARequestHandler : public AsyncWebHandler {
|
|||||||
uint32_t last_ota_progress_{0};
|
uint32_t last_ota_progress_{0};
|
||||||
uint32_t ota_read_length_{0};
|
uint32_t ota_read_length_{0};
|
||||||
WebServerBase *parent_;
|
WebServerBase *parent_;
|
||||||
|
bool ota_success_{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef USE_ESP_IDF
|
std::unique_ptr<ota_base::OTABackend> ota_backend_{nullptr};
|
||||||
void *ota_backend_{nullptr};
|
|
||||||
bool ota_success_{false};
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
#endif // USE_WEBSERVER_OTA
|
#endif // USE_WEBSERVER_OTA
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ void Application::setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "setup() finished successfully!");
|
ESP_LOGI(TAG, "setup() finished successfully!");
|
||||||
|
|
||||||
|
// Clear setup priority overrides to free memory
|
||||||
|
clear_setup_priority_overrides();
|
||||||
|
|
||||||
this->schedule_dump_config();
|
this->schedule_dump_config();
|
||||||
this->calculate_looping_components_();
|
this->calculate_looping_components_();
|
||||||
}
|
}
|
||||||
@@ -137,6 +141,10 @@ void Application::loop() {
|
|||||||
this->in_loop_ = false;
|
this->in_loop_ = false;
|
||||||
this->app_state_ = new_app_state;
|
this->app_state_ = new_app_state;
|
||||||
|
|
||||||
|
// Process any pending runtime stats printing after all components have run
|
||||||
|
// This ensures stats printing doesn't affect component timing measurements
|
||||||
|
runtime_stats.process_pending_stats(last_op_end_time);
|
||||||
|
|
||||||
// Use the last component's end time instead of calling millis() again
|
// Use the last component's end time instead of calling millis() again
|
||||||
auto elapsed = last_op_end_time - this->last_loop_;
|
auto elapsed = last_op_end_time - this->last_loop_;
|
||||||
if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) {
|
if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/preferences.h"
|
#include "esphome/core/preferences.h"
|
||||||
|
#include "esphome/core/runtime_stats.h"
|
||||||
#include "esphome/core/scheduler.h"
|
#include "esphome/core/scheduler.h"
|
||||||
|
|
||||||
#ifdef USE_DEVICES
|
#ifdef USE_DEVICES
|
||||||
@@ -348,6 +349,18 @@ class Application {
|
|||||||
|
|
||||||
uint32_t get_loop_interval() const { return static_cast<uint32_t>(this->loop_interval_); }
|
uint32_t get_loop_interval() const { return static_cast<uint32_t>(this->loop_interval_); }
|
||||||
|
|
||||||
|
/** Enable or disable runtime statistics collection.
|
||||||
|
*
|
||||||
|
* @param enable Whether to enable runtime statistics collection.
|
||||||
|
*/
|
||||||
|
void set_runtime_stats_enabled(bool enable) { runtime_stats.set_enabled(enable); }
|
||||||
|
|
||||||
|
/** Set the interval at which runtime statistics are logged.
|
||||||
|
*
|
||||||
|
* @param interval The interval in milliseconds between logging of runtime statistics.
|
||||||
|
*/
|
||||||
|
void set_runtime_stats_log_interval(uint32_t interval) { runtime_stats.set_log_interval(interval); }
|
||||||
|
|
||||||
void schedule_dump_config() { this->dump_config_at_ = 0; }
|
void schedule_dump_config() { this->dump_config_at_ = 0; }
|
||||||
|
|
||||||
void feed_wdt(uint32_t time = 0);
|
void feed_wdt(uint32_t time = 0);
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
@@ -12,6 +14,30 @@ namespace esphome {
|
|||||||
|
|
||||||
static const char *const TAG = "component";
|
static const char *const TAG = "component";
|
||||||
|
|
||||||
|
// Global vectors for component data that doesn't belong in every instance.
|
||||||
|
// Using vector instead of unordered_map for both because:
|
||||||
|
// - Much lower memory overhead (8 bytes per entry vs 20+ for unordered_map)
|
||||||
|
// - Linear search is fine for small n (typically < 5 entries)
|
||||||
|
// - These are rarely accessed (setup only or error cases only)
|
||||||
|
|
||||||
|
// Component error messages - only stores messages for failed components
|
||||||
|
// Lazy allocated since most configs have zero failures
|
||||||
|
// Note: We don't clear this vector because:
|
||||||
|
// 1. Components are never destroyed in ESPHome
|
||||||
|
// 2. Failed components remain failed (no recovery mechanism)
|
||||||
|
// 3. Memory usage is minimal (only failures with custom messages are stored)
|
||||||
|
static std::unique_ptr<std::vector<std::pair<const Component *, const char *>>> &get_component_error_messages() {
|
||||||
|
static std::unique_ptr<std::vector<std::pair<const Component *, const char *>>> instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup priority overrides - freed after setup completes
|
||||||
|
// Typically < 5 entries, lazy allocated
|
||||||
|
static std::unique_ptr<std::vector<std::pair<const Component *, float>>> &get_setup_priority_overrides() {
|
||||||
|
static std::unique_ptr<std::vector<std::pair<const Component *, float>>> instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
namespace setup_priority {
|
namespace setup_priority {
|
||||||
|
|
||||||
const float BUS = 1000.0f;
|
const float BUS = 1000.0f;
|
||||||
@@ -102,8 +128,17 @@ void Component::call_setup() { this->setup(); }
|
|||||||
void Component::call_dump_config() {
|
void Component::call_dump_config() {
|
||||||
this->dump_config();
|
this->dump_config();
|
||||||
if (this->is_failed()) {
|
if (this->is_failed()) {
|
||||||
ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(),
|
// Look up error message from global vector
|
||||||
this->error_message_ ? this->error_message_ : "unspecified");
|
const char *error_msg = "unspecified";
|
||||||
|
if (get_component_error_messages()) {
|
||||||
|
for (const auto &pair : *get_component_error_messages()) {
|
||||||
|
if (pair.first == this) {
|
||||||
|
error_msg = pair.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(), error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,8 +280,21 @@ void Component::status_set_error(const char *message) {
|
|||||||
this->component_state_ |= STATUS_LED_ERROR;
|
this->component_state_ |= STATUS_LED_ERROR;
|
||||||
App.app_state_ |= STATUS_LED_ERROR;
|
App.app_state_ |= STATUS_LED_ERROR;
|
||||||
ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
|
ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
|
||||||
if (strcmp(message, "unspecified") != 0)
|
if (strcmp(message, "unspecified") != 0) {
|
||||||
this->error_message_ = message;
|
// Lazy allocate the error messages vector if needed
|
||||||
|
if (!get_component_error_messages()) {
|
||||||
|
get_component_error_messages() = std::make_unique<std::vector<std::pair<const Component *, const char *>>>();
|
||||||
|
}
|
||||||
|
// Check if this component already has an error message
|
||||||
|
for (auto &pair : *get_component_error_messages()) {
|
||||||
|
if (pair.first == this) {
|
||||||
|
pair.second = message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add new error message
|
||||||
|
get_component_error_messages()->emplace_back(this, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void Component::status_clear_warning() {
|
void Component::status_clear_warning() {
|
||||||
if ((this->component_state_ & STATUS_LED_WARNING) == 0)
|
if ((this->component_state_ & STATUS_LED_WARNING) == 0)
|
||||||
@@ -270,11 +318,36 @@ void Component::status_momentary_error(const std::string &name, uint32_t length)
|
|||||||
}
|
}
|
||||||
void Component::dump_config() {}
|
void Component::dump_config() {}
|
||||||
float Component::get_actual_setup_priority() const {
|
float Component::get_actual_setup_priority() const {
|
||||||
if (std::isnan(this->setup_priority_override_))
|
// Check if there's an override in the global vector
|
||||||
return this->get_setup_priority();
|
if (get_setup_priority_overrides()) {
|
||||||
return this->setup_priority_override_;
|
// Linear search is fine for small n (typically < 5 overrides)
|
||||||
|
for (const auto &pair : *get_setup_priority_overrides()) {
|
||||||
|
if (pair.first == this) {
|
||||||
|
return pair.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this->get_setup_priority();
|
||||||
|
}
|
||||||
|
void Component::set_setup_priority(float priority) {
|
||||||
|
// Lazy allocate the vector if needed
|
||||||
|
if (!get_setup_priority_overrides()) {
|
||||||
|
get_setup_priority_overrides() = std::make_unique<std::vector<std::pair<const Component *, float>>>();
|
||||||
|
// Reserve some space to avoid reallocations (most configs have < 10 overrides)
|
||||||
|
get_setup_priority_overrides()->reserve(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this component already has an override
|
||||||
|
for (auto &pair : *get_setup_priority_overrides()) {
|
||||||
|
if (pair.first == this) {
|
||||||
|
pair.second = priority;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new override
|
||||||
|
get_setup_priority_overrides()->emplace_back(this, priority);
|
||||||
}
|
}
|
||||||
void Component::set_setup_priority(float priority) { this->setup_priority_override_ = priority; }
|
|
||||||
|
|
||||||
bool Component::has_overridden_loop() const {
|
bool Component::has_overridden_loop() const {
|
||||||
#if defined(USE_HOST) || defined(CLANG_TIDY)
|
#if defined(USE_HOST) || defined(CLANG_TIDY)
|
||||||
@@ -319,6 +392,9 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
|
|||||||
uint32_t curr_time = millis();
|
uint32_t curr_time = millis();
|
||||||
|
|
||||||
uint32_t blocking_time = curr_time - this->started_;
|
uint32_t blocking_time = curr_time - this->started_;
|
||||||
|
|
||||||
|
// Record component runtime stats
|
||||||
|
runtime_stats.record_component_time(this->component_, blocking_time, curr_time);
|
||||||
bool should_warn;
|
bool should_warn;
|
||||||
if (this->component_ != nullptr) {
|
if (this->component_ != nullptr) {
|
||||||
should_warn = this->component_->should_warn_of_blocking(blocking_time);
|
should_warn = this->component_->should_warn_of_blocking(blocking_time);
|
||||||
@@ -336,4 +412,9 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
|
|||||||
|
|
||||||
WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() {}
|
WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() {}
|
||||||
|
|
||||||
|
void clear_setup_priority_overrides() {
|
||||||
|
// Free the setup priority map completely
|
||||||
|
get_setup_priority_overrides().reset();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "esphome/core/optional.h"
|
#include "esphome/core/optional.h"
|
||||||
|
#include "esphome/core/runtime_stats.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
@@ -387,9 +388,7 @@ class Component {
|
|||||||
bool cancel_defer(const std::string &name); // NOLINT
|
bool cancel_defer(const std::string &name); // NOLINT
|
||||||
|
|
||||||
// Ordered for optimal packing on 32-bit systems
|
// Ordered for optimal packing on 32-bit systems
|
||||||
float setup_priority_override_{NAN};
|
|
||||||
const char *component_source_{nullptr};
|
const char *component_source_{nullptr};
|
||||||
const char *error_message_{nullptr};
|
|
||||||
uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)
|
uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)
|
||||||
/// State of this component - each bit has a purpose:
|
/// State of this component - each bit has a purpose:
|
||||||
/// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
|
/// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
|
||||||
@@ -459,4 +458,7 @@ class WarnIfComponentBlockingGuard {
|
|||||||
Component *component_;
|
Component *component_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Function to clear setup priority overrides after all components are set up
|
||||||
|
void clear_setup_priority_overrides();
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|||||||
92
esphome/core/runtime_stats.cpp
Normal file
92
esphome/core/runtime_stats.cpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "esphome/core/runtime_stats.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
|
||||||
|
RuntimeStatsCollector runtime_stats;
|
||||||
|
|
||||||
|
void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time) {
|
||||||
|
if (!this->enabled_ || component == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if we have cached the name for this component
|
||||||
|
auto name_it = this->component_names_cache_.find(component);
|
||||||
|
if (name_it == this->component_names_cache_.end()) {
|
||||||
|
// First time seeing this component, cache its name
|
||||||
|
const char *source = component->get_component_source();
|
||||||
|
this->component_names_cache_[component] = source;
|
||||||
|
this->component_stats_[source].record_time(duration_ms);
|
||||||
|
} else {
|
||||||
|
// Use cached name - no string operations, just map lookup
|
||||||
|
this->component_stats_[name_it->second].record_time(duration_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If next_log_time_ is 0, initialize it
|
||||||
|
if (this->next_log_time_ == 0) {
|
||||||
|
this->next_log_time_ = current_time + this->log_interval_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't print stats here anymore - let process_pending_stats handle it
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStatsCollector::log_stats_() {
|
||||||
|
ESP_LOGI(RUNTIME_TAG, "Component Runtime Statistics");
|
||||||
|
ESP_LOGI(RUNTIME_TAG, "Period stats (last %" PRIu32 "ms):", this->log_interval_);
|
||||||
|
|
||||||
|
// First collect stats we want to display
|
||||||
|
std::vector<ComponentStatPair> stats_to_display;
|
||||||
|
|
||||||
|
for (const auto &it : this->component_stats_) {
|
||||||
|
const ComponentRuntimeStats &stats = it.second;
|
||||||
|
if (stats.get_period_count() > 0) {
|
||||||
|
ComponentStatPair pair = {it.first, &stats};
|
||||||
|
stats_to_display.push_back(pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by period runtime (descending)
|
||||||
|
std::sort(stats_to_display.begin(), stats_to_display.end(), std::greater<ComponentStatPair>());
|
||||||
|
|
||||||
|
// Log top components by period runtime
|
||||||
|
for (const auto &it : stats_to_display) {
|
||||||
|
const std::string &source = it.name;
|
||||||
|
const ComponentRuntimeStats *stats = it.stats;
|
||||||
|
|
||||||
|
ESP_LOGI(RUNTIME_TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source.c_str(),
|
||||||
|
stats->get_period_count(), stats->get_period_avg_time_ms(), stats->get_period_max_time_ms(),
|
||||||
|
stats->get_period_time_ms());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log total stats since boot
|
||||||
|
ESP_LOGI(RUNTIME_TAG, "Total stats (since boot):");
|
||||||
|
|
||||||
|
// Re-sort by total runtime for all-time stats
|
||||||
|
std::sort(stats_to_display.begin(), stats_to_display.end(),
|
||||||
|
[](const ComponentStatPair &a, const ComponentStatPair &b) {
|
||||||
|
return a.stats->get_total_time_ms() > b.stats->get_total_time_ms();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto &it : stats_to_display) {
|
||||||
|
const std::string &source = it.name;
|
||||||
|
const ComponentRuntimeStats *stats = it.stats;
|
||||||
|
|
||||||
|
ESP_LOGI(RUNTIME_TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source.c_str(),
|
||||||
|
stats->get_total_count(), stats->get_total_avg_time_ms(), stats->get_total_max_time_ms(),
|
||||||
|
stats->get_total_time_ms());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStatsCollector::process_pending_stats(uint32_t current_time) {
|
||||||
|
if (!this->enabled_ || this->next_log_time_ == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (current_time >= this->next_log_time_) {
|
||||||
|
this->log_stats_();
|
||||||
|
this->reset_stats_();
|
||||||
|
this->next_log_time_ = current_time + this->log_interval_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
121
esphome/core/runtime_stats.h
Normal file
121
esphome/core/runtime_stats.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
|
||||||
|
static const char *const RUNTIME_TAG = "runtime";
|
||||||
|
|
||||||
|
class Component; // Forward declaration
|
||||||
|
|
||||||
|
class ComponentRuntimeStats {
|
||||||
|
public:
|
||||||
|
ComponentRuntimeStats()
|
||||||
|
: period_count_(0),
|
||||||
|
total_count_(0),
|
||||||
|
period_time_ms_(0),
|
||||||
|
total_time_ms_(0),
|
||||||
|
period_max_time_ms_(0),
|
||||||
|
total_max_time_ms_(0) {}
|
||||||
|
|
||||||
|
void record_time(uint32_t duration_ms) {
|
||||||
|
// Update period counters
|
||||||
|
this->period_count_++;
|
||||||
|
this->period_time_ms_ += duration_ms;
|
||||||
|
if (duration_ms > this->period_max_time_ms_)
|
||||||
|
this->period_max_time_ms_ = duration_ms;
|
||||||
|
|
||||||
|
// Update total counters
|
||||||
|
this->total_count_++;
|
||||||
|
this->total_time_ms_ += duration_ms;
|
||||||
|
if (duration_ms > this->total_max_time_ms_)
|
||||||
|
this->total_max_time_ms_ = duration_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_period_stats() {
|
||||||
|
this->period_count_ = 0;
|
||||||
|
this->period_time_ms_ = 0;
|
||||||
|
this->period_max_time_ms_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period stats (reset each logging interval)
|
||||||
|
uint32_t get_period_count() const { return this->period_count_; }
|
||||||
|
uint32_t get_period_time_ms() const { return this->period_time_ms_; }
|
||||||
|
uint32_t get_period_max_time_ms() const { return this->period_max_time_ms_; }
|
||||||
|
float get_period_avg_time_ms() const {
|
||||||
|
return this->period_count_ > 0 ? this->period_time_ms_ / static_cast<float>(this->period_count_) : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total stats (persistent until reboot)
|
||||||
|
uint32_t get_total_count() const { return this->total_count_; }
|
||||||
|
uint32_t get_total_time_ms() const { return this->total_time_ms_; }
|
||||||
|
uint32_t get_total_max_time_ms() const { return this->total_max_time_ms_; }
|
||||||
|
float get_total_avg_time_ms() const {
|
||||||
|
return this->total_count_ > 0 ? this->total_time_ms_ / static_cast<float>(this->total_count_) : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Period stats (reset each logging interval)
|
||||||
|
uint32_t period_count_;
|
||||||
|
uint32_t period_time_ms_;
|
||||||
|
uint32_t period_max_time_ms_;
|
||||||
|
|
||||||
|
// Total stats (persistent until reboot)
|
||||||
|
uint32_t total_count_;
|
||||||
|
uint32_t total_time_ms_;
|
||||||
|
uint32_t total_max_time_ms_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// For sorting components by run time
|
||||||
|
struct ComponentStatPair {
|
||||||
|
std::string name;
|
||||||
|
const ComponentRuntimeStats *stats;
|
||||||
|
|
||||||
|
bool operator>(const ComponentStatPair &other) const {
|
||||||
|
// Sort by period time as that's what we're displaying in the logs
|
||||||
|
return stats->get_period_time_ms() > other.stats->get_period_time_ms();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RuntimeStatsCollector {
|
||||||
|
public:
|
||||||
|
RuntimeStatsCollector() : log_interval_(60000), next_log_time_(0), enabled_(true) {}
|
||||||
|
|
||||||
|
void set_log_interval(uint32_t log_interval) { this->log_interval_ = log_interval; }
|
||||||
|
uint32_t get_log_interval() const { return this->log_interval_; }
|
||||||
|
|
||||||
|
void set_enabled(bool enabled) { this->enabled_ = enabled; }
|
||||||
|
bool is_enabled() const { return this->enabled_; }
|
||||||
|
|
||||||
|
void record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time);
|
||||||
|
|
||||||
|
// Process any pending stats printing (should be called after component loop)
|
||||||
|
void process_pending_stats(uint32_t current_time);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void log_stats_();
|
||||||
|
|
||||||
|
void reset_stats_() {
|
||||||
|
for (auto &it : this->component_stats_) {
|
||||||
|
it.second.reset_period_stats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back to string keys, but we'll cache the source name per component
|
||||||
|
std::map<std::string, ComponentRuntimeStats> component_stats_;
|
||||||
|
std::map<Component *, std::string> component_names_cache_;
|
||||||
|
uint32_t log_interval_;
|
||||||
|
uint32_t next_log_time_;
|
||||||
|
bool enabled_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global instance for runtime stats collection
|
||||||
|
extern RuntimeStatsCollector runtime_stats;
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
@@ -526,9 +526,13 @@ class BytesType(TypeInfo):
|
|||||||
reference_type = "std::string &"
|
reference_type = "std::string &"
|
||||||
const_reference_type = "const std::string &"
|
const_reference_type = "const std::string &"
|
||||||
decode_length = "value.as_string()"
|
decode_length = "value.as_string()"
|
||||||
encode_func = "encode_string"
|
encode_func = "encode_bytes"
|
||||||
wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2
|
wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def encode_content(self) -> str:
|
||||||
|
return f"buffer.encode_bytes({self.number}, reinterpret_cast<const uint8_t*>(this->{self.field_name}.data()), this->{self.field_name}.size());"
|
||||||
|
|
||||||
def dump(self, name: str) -> str:
|
def dump(self, name: str) -> str:
|
||||||
o = f'out.append("\'").append({name}).append("\'");'
|
o = f'out.append("\'").append({name}).append("\'");'
|
||||||
return o
|
return o
|
||||||
|
|||||||
10
tests/components/ota_base/common.yaml
Normal file
10
tests/components/ota_base/common.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Test that ota_base compiles correctly as a dependency
|
||||||
|
# This component is typically auto-loaded by other components
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: MySSID
|
||||||
|
password: password1
|
||||||
|
|
||||||
|
ota:
|
||||||
|
- platform: esphome
|
||||||
|
password: "test1234"
|
||||||
1
tests/components/ota_base/test.esp32-idf.yaml
Normal file
1
tests/components/ota_base/test.esp32-idf.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<<: !include common.yaml
|
||||||
Reference in New Issue
Block a user