mirror of
https://github.com/esphome/esphome.git
synced 2025-08-10 12:27:46 +00:00
Compare commits
1910 Commits
dev
...
revert_loo
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f88208d518 | ||
![]() |
0b2270c1d0 | ||
![]() |
bfae905a2b | ||
![]() |
5b8ae6ed1a | ||
![]() |
1b74c877e1 | ||
![]() |
edeee42fd9 | ||
![]() |
8ae2b31a2f | ||
![]() |
aefb53cb0e | ||
![]() |
0fea9aab99 | ||
![]() |
e5001734ce | ||
![]() |
39f79522db | ||
![]() |
9bceed2cfc | ||
![]() |
c400d8e5a9 | ||
![]() |
e6961f8f24 | ||
![]() |
0b9b33b81b | ||
![]() |
d71f2ad185 | ||
![]() |
f92571e767 | ||
![]() |
efa3d32fce | ||
![]() |
ac19d5eba2 | ||
![]() |
ffcf2229f6 | ||
![]() |
157c4f4369 | ||
![]() |
2a935d9238 | ||
![]() |
d4556608c8 | ||
![]() |
285ad9af1e | ||
![]() |
f15662d4b5 | ||
![]() |
fffa6eb0db | ||
![]() |
6711742248 | ||
![]() |
d624f2a9ce | ||
![]() |
c590ffd289 | ||
![]() |
8096eea6c3 | ||
![]() |
873aebc572 | ||
![]() |
5adc58f826 | ||
![]() |
3d35b9679a | ||
![]() |
fbd3c051ec | ||
![]() |
26b77e0f06 | ||
![]() |
f3030e35a8 | ||
![]() |
adc21eef70 | ||
![]() |
93fdea954f | ||
![]() |
bb81a40b7c | ||
![]() |
922692338f | ||
![]() |
2088deeacb | ||
![]() |
0534d1bfcf | ||
![]() |
b8e326eb01 | ||
![]() |
58d7533128 | ||
![]() |
444c77775f | ||
![]() |
2310610aa0 | ||
![]() |
7dec484eae | ||
![]() |
712d3dee98 | ||
![]() |
44d7147ea4 | ||
![]() |
ede8e542bc | ||
![]() |
e17fef3208 | ||
![]() |
7f25d3e6d3 | ||
![]() |
72fd984d4b | ||
![]() |
97525cfe87 | ||
![]() |
8f201cdb7e | ||
![]() |
d0511e118d | ||
![]() |
c120676d19 | ||
![]() |
bd52acff12 | ||
![]() |
22422fc3dd | ||
![]() |
70c9cf9d95 | ||
![]() |
b0aafb1226 | ||
![]() |
c4ac22286f | ||
![]() |
4a0716d7ba | ||
![]() |
4f17c352db | ||
![]() |
37d24dd707 | ||
![]() |
a508d9dd3a | ||
![]() |
48436ec7c8 | ||
![]() |
daf241b3f6 | ||
![]() |
4c62f43dcd | ||
![]() |
767ec53cfa | ||
![]() |
7b9acd39e1 | ||
![]() |
55272dd0fd | ||
![]() |
bc6b1ffc14 | ||
![]() |
b3abebfb37 | ||
![]() |
f034069b5e | ||
![]() |
9a391df0f0 | ||
![]() |
6d6bf82501 | ||
![]() |
5f14579af8 | ||
![]() |
8ee06cdc8c | ||
![]() |
37cbcd5110 | ||
![]() |
91e1a4ff76 | ||
![]() |
ed190a92b1 | ||
![]() |
b660c867fb | ||
![]() |
4cdef8c001 | ||
![]() |
a1667b29f1 | ||
![]() |
74fe8bd022 | ||
![]() |
b38faa1870 | ||
![]() |
524d69a238 | ||
![]() |
4a39f14037 | ||
![]() |
b66c6dd856 | ||
![]() |
504c67f59f | ||
![]() |
383791418b | ||
![]() |
0240a7c310 | ||
![]() |
0be1395647 | ||
![]() |
daae3a93ab | ||
![]() |
00eba20ea9 | ||
![]() |
31caacabf0 | ||
![]() |
8a7446a1ea | ||
![]() |
1395af2c1c | ||
![]() |
ebf225d5f2 | ||
![]() |
b6aca30c42 | ||
![]() |
b5da9b0e7c | ||
![]() |
38d38d6e8c | ||
![]() |
fffc324c6e | ||
![]() |
3d832e4d92 | ||
![]() |
85ab9d3eec | ||
![]() |
67b9c249d4 | ||
![]() |
c66726336c | ||
![]() |
54158bf5f1 | ||
![]() |
edc641cfa3 | ||
![]() |
12994c3a29 | ||
![]() |
a63ebf2c5e | ||
![]() |
839a26c289 | ||
![]() |
9e6481c492 | ||
![]() |
311888ac6d | ||
![]() |
7e86aefa91 | ||
![]() |
756fc89eab | ||
![]() |
c8140e966a | ||
![]() |
eff866c222 | ||
![]() |
ffaba916d7 | ||
![]() |
1de659420e | ||
![]() |
d9210eba69 | ||
![]() |
4a8f6ce556 | ||
![]() |
8c11241af0 | ||
![]() |
b24ff7236e | ||
![]() |
5e906b1dd9 | ||
![]() |
ad52d80281 | ||
![]() |
04953db51e | ||
![]() |
8b74333e8b | ||
![]() |
5fb97e8e3c | ||
![]() |
8b09a5259e | ||
![]() |
ae7aa4c0ef | ||
![]() |
9cb86241b9 | ||
![]() |
1dc736e27a | ||
![]() |
7de63d0670 | ||
![]() |
54bbde6183 | ||
![]() |
8b54e46652 | ||
![]() |
14e2c85028 | ||
![]() |
9cd1c7a355 | ||
![]() |
e2a0879239 | ||
![]() |
197b04d74f | ||
![]() |
852671945a | ||
![]() |
8a296e013c | ||
![]() |
953c05d4da | ||
![]() |
af061d6cd8 | ||
![]() |
836ea5c60a | ||
![]() |
58f79ef654 | ||
![]() |
984d10aff1 | ||
![]() |
48ddb5c999 | ||
![]() |
cc34cc7a4e | ||
![]() |
59e567e567 | ||
![]() |
a45be553ed | ||
![]() |
ff59e37d8d | ||
![]() |
d251d78002 | ||
![]() |
55833380c1 | ||
![]() |
16bd3f92c4 | ||
![]() |
e1e95c36c5 | ||
![]() |
2e7826aa34 | ||
![]() |
e1be941bda | ||
![]() |
eea7b9843b | ||
![]() |
a626053220 | ||
![]() |
a5f22e99a3 | ||
![]() |
fb44fddacf | ||
![]() |
72fcb29fd2 | ||
![]() |
29988d414c | ||
![]() |
82970b640f | ||
![]() |
af724ffb15 | ||
![]() |
82dfd0a233 | ||
![]() |
7688cc619b | ||
![]() |
232d3a8b89 | ||
![]() |
a976df4da8 | ||
![]() |
f9744dabc1 | ||
![]() |
79acf97c48 | ||
![]() |
8becc57835 | ||
![]() |
f6b989bd9a | ||
![]() |
109eae26a7 | ||
![]() |
8496102eb6 | ||
![]() |
04d7213ede | ||
![]() |
2ebb17a05e | ||
![]() |
905263548d | ||
![]() |
83c0589c06 | ||
![]() |
acc8b57709 | ||
![]() |
8621bca535 | ||
![]() |
fc4c383409 | ||
![]() |
a5ed8db5bd | ||
![]() |
3060e2cbc3 | ||
![]() |
1cc507b211 | ||
![]() |
b88061843c | ||
![]() |
1d6fcafefc | ||
![]() |
bc57cdb71a | ||
![]() |
b70007852d | ||
![]() |
9f6cd1f809 | ||
![]() |
3905085614 | ||
![]() |
722df19758 | ||
![]() |
0046e67727 | ||
![]() |
7e3027d9bd | ||
![]() |
d0307cec4f | ||
![]() |
1bc7b805c0 | ||
![]() |
79e20ed894 | ||
![]() |
b125cd6979 | ||
![]() |
0582fee82c | ||
![]() |
cd4a10e4e1 | ||
![]() |
3400cdf4c0 | ||
![]() |
d72fe6ea4b | ||
![]() |
2ca306c1c1 | ||
![]() |
3ad551b27e | ||
![]() |
9682c6c3d7 | ||
![]() |
d67508a6eb | ||
![]() |
b25206b7bb | ||
![]() |
112c6e34a5 | ||
![]() |
2ed70c3c60 | ||
![]() |
9119ac1c32 | ||
![]() |
152e3ee587 | ||
![]() |
acbcc5f9b8 | ||
![]() |
5ed589fc97 | ||
![]() |
58696961bd | ||
![]() |
a5f5af9596 | ||
![]() |
fde80bc530 | ||
![]() |
211739bba0 | ||
![]() |
23f0c596c2 | ||
![]() |
dec3c69190 | ||
![]() |
3204cf52e9 | ||
![]() |
e2d509d63d | ||
![]() |
00dd5d64de | ||
![]() |
09705ca526 | ||
![]() |
8223db761d | ||
![]() |
9dddb749c5 | ||
![]() |
e2524c9764 | ||
![]() |
03a2237f2e | ||
![]() |
ba62a368ff | ||
![]() |
ffbadc0929 | ||
![]() |
d19e2d9cce | ||
![]() |
c7884253d2 | ||
![]() |
fd2e6b1d2d | ||
![]() |
6b8da2f0ca | ||
![]() |
45e9522221 | ||
![]() |
8084c19a6c | ||
![]() |
2c63d5c7ce | ||
![]() |
6a728c2d7d | ||
![]() |
7afb2fe077 | ||
![]() |
57c0a44b55 | ||
![]() |
b2ec2615bb | ||
![]() |
6a566c6305 | ||
![]() |
da1e1ce9ce | ||
![]() |
9902a4ee9c | ||
![]() |
2ce0753ec6 | ||
![]() |
e4736e9aa7 | ||
![]() |
8acd7548c6 | ||
![]() |
1ca1ceb08d | ||
![]() |
3087ccface | ||
![]() |
d9fe52a5fb | ||
![]() |
56fdc1d115 | ||
![]() |
a8dd0b474a | ||
![]() |
4c9fa2f753 | ||
![]() |
1c4a50ad3a | ||
![]() |
9f5584ac62 | ||
![]() |
27db5352ac | ||
![]() |
5f13aa162d | ||
![]() |
9aa53fd140 | ||
![]() |
b9afa119a0 | ||
![]() |
1a62b75ec3 | ||
![]() |
15693a9cf0 | ||
![]() |
a62a8c3d94 | ||
![]() |
8593da7426 | ||
![]() |
0ce077db94 | ||
![]() |
512cc24dc7 | ||
![]() |
cd6d686fd6 | ||
![]() |
eeb827e88f | ||
![]() |
a8324e84f0 | ||
![]() |
a23f33cbad | ||
![]() |
bab6fdcf4e | ||
![]() |
a1e74802ea | ||
![]() |
5be2339bb5 | ||
![]() |
9a0ab594ef | ||
![]() |
fbf615f73c | ||
![]() |
186e64931a | ||
![]() |
6e7e2b4471 | ||
![]() |
6b83975df0 | ||
![]() |
f52fe63ad1 | ||
![]() |
4723f767f4 | ||
![]() |
cc1abfcdb3 | ||
![]() |
d6422b6d25 | ||
![]() |
cde4fc0609 | ||
![]() |
7f5eefed10 | ||
![]() |
1aab2f5a7f | ||
![]() |
7566d85941 | ||
![]() |
db59f3ae88 | ||
![]() |
dc7b39722d | ||
![]() |
19ab40e5c2 | ||
![]() |
8a2599b7c2 | ||
![]() |
0a45014330 | ||
![]() |
10605e93cd | ||
![]() |
0f65731673 | ||
![]() |
5f9331b112 | ||
![]() |
94f49ab9da | ||
![]() |
603d4cfcf9 | ||
![]() |
759fe53fd4 | ||
![]() |
61a965019f | ||
![]() |
a91d0e5c2f | ||
![]() |
e26c20910d | ||
![]() |
6740561bd7 | ||
![]() |
04820ede37 | ||
![]() |
732370effc | ||
![]() |
03f52e741b | ||
![]() |
f5c6e03404 | ||
![]() |
ee7bda74c0 | ||
![]() |
d40fcb324c | ||
![]() |
126f7acad2 | ||
![]() |
f9357f5e6e | ||
![]() |
81281c181f | ||
![]() |
c17fdd91de | ||
![]() |
1f0958e824 | ||
![]() |
9291dc4e27 | ||
![]() |
72419eb540 | ||
![]() |
dbbcbc0998 | ||
![]() |
7c45afa338 | ||
![]() |
984601f0b2 | ||
![]() |
ee600ced31 | ||
![]() |
c3da5b7a3f | ||
![]() |
ce21b992e3 | ||
![]() |
88323bcca0 | ||
![]() |
121759c07d | ||
![]() |
f1d2300153 | ||
![]() |
94fd2d8ca1 | ||
![]() |
c51bae3640 | ||
![]() |
a399e90ed6 | ||
![]() |
e164e6ce37 | ||
![]() |
cb0ef0b54a | ||
![]() |
73a8c03562 | ||
![]() |
e1583ff2d3 | ||
![]() |
969fc54409 | ||
![]() |
8ba14d1f54 | ||
![]() |
6aeefdc085 | ||
![]() |
9d10c79491 | ||
![]() |
b50bd00207 | ||
![]() |
472a594c6d | ||
![]() |
3e6da2870a | ||
![]() |
d999ef3047 | ||
![]() |
e5bd2bd31b | ||
![]() |
fc30ca83ca | ||
![]() |
5dc7dee6d6 | ||
![]() |
5aa4ed8d87 | ||
![]() |
5c4ded83d0 | ||
![]() |
7744b2db79 | ||
![]() |
8fcbcebf84 | ||
![]() |
561ed32b2a | ||
![]() |
5adfb71fe1 | ||
![]() |
dfdec8ec0a | ||
![]() |
f6c12229e5 | ||
![]() |
c80481baab | ||
![]() |
86ceccbb1c | ||
![]() |
628caf63fc | ||
![]() |
1ce5a994d8 | ||
![]() |
2abccce297 | ||
![]() |
0448a66960 | ||
![]() |
1a36c3cec4 | ||
![]() |
b497f11af0 | ||
![]() |
07f16dc065 | ||
![]() |
d2deba6b69 | ||
![]() |
545fa1f1bc | ||
![]() |
a477249266 | ||
![]() |
b974ccabac | ||
![]() |
8f38be0914 | ||
![]() |
2b12307b49 | ||
![]() |
e340d61a85 | ||
![]() |
0110a376b7 | ||
![]() |
c739a33be0 | ||
![]() |
0f6dad9c62 | ||
![]() |
58541aa739 | ||
![]() |
4c91dead3d | ||
![]() |
78a0fecc08 | ||
![]() |
ff7a3d9f55 | ||
![]() |
42e1b1a2c1 | ||
![]() |
0d360938c2 | ||
![]() |
36ca3546f5 | ||
![]() |
5536bdf0c9 | ||
![]() |
1718591ac1 | ||
![]() |
5aaa99d0e4 | ||
![]() |
60e9ad2240 | ||
![]() |
5ec25d84be | ||
![]() |
74b0a29a52 | ||
![]() |
909356698c | ||
![]() |
bd416e761e | ||
![]() |
f34fe95f1c | ||
![]() |
388fde1ee8 | ||
![]() |
b13842f44e | ||
![]() |
2396bf412d | ||
![]() |
1229766436 | ||
![]() |
3fa899776d | ||
![]() |
77a5430f00 | ||
![]() |
f27ef9210a | ||
![]() |
8ac6075321 | ||
![]() |
6e1e8ed321 | ||
![]() |
0826ade69d | ||
![]() |
cf9130f906 | ||
![]() |
d268c14f7e | ||
![]() |
3cca7a6161 | ||
![]() |
52d6801618 | ||
![]() |
a714e8da0b | ||
![]() |
1778776b73 | ||
![]() |
d6e05061f8 | ||
![]() |
13ceda899b | ||
![]() |
40d436746c | ||
![]() |
5c59b4fcad | ||
![]() |
4de36ffeb4 | ||
![]() |
4b3393ce64 | ||
![]() |
4c8bb878bf | ||
![]() |
8a3cb32531 | ||
![]() |
d3ab7f320e | ||
![]() |
85351bb952 | ||
![]() |
b47f9158b2 | ||
![]() |
ee5242ec8d | ||
![]() |
238909c0de | ||
![]() |
fe9316c95d | ||
![]() |
a7e74bb7de | ||
![]() |
b9cb690986 | ||
![]() |
808066f564 | ||
![]() |
2057af8396 | ||
![]() |
b95449615f | ||
![]() |
5e8f1d82c3 | ||
![]() |
6afda9d4dc | ||
![]() |
4f10a0ccf7 | ||
![]() |
96d39403f4 | ||
![]() |
aeb56cc3d0 | ||
![]() |
33389f9c7f | ||
![]() |
55a7926670 | ||
![]() |
f76cba0af6 | ||
![]() |
1dc75f6ffa | ||
![]() |
acb0fdc288 | ||
![]() |
de235b638a | ||
![]() |
ab454e9928 | ||
![]() |
0a8af3ec85 | ||
![]() |
51eecac2de | ||
![]() |
815744b0f6 | ||
![]() |
a1281febe9 | ||
![]() |
9ef982fa4d | ||
![]() |
44f97e2de4 | ||
![]() |
8ad4d3b6f5 | ||
![]() |
d97f473e4a | ||
![]() |
ef072eb655 | ||
![]() |
8040c7cd92 | ||
![]() |
8648acab5d | ||
![]() |
1155e9b88a | ||
![]() |
c069a66625 | ||
![]() |
2a10f58bdd | ||
![]() |
e713b0bd8c | ||
![]() |
6ed5ea87f1 | ||
![]() |
fd13ed78ab | ||
![]() |
221f380ca3 | ||
![]() |
cf472d5281 | ||
![]() |
85fa884382 | ||
![]() |
6cd443e9dc | ||
![]() |
26b12ee790 | ||
![]() |
b1c6ece50d | ||
![]() |
c8c1573fbb | ||
![]() |
e7fb069bb3 | ||
![]() |
fe7e5feba7 | ||
![]() |
1abdc23a23 | ||
![]() |
c59c5db03e | ||
![]() |
2076d615f0 | ||
![]() |
ec3660e8ae | ||
![]() |
f6251cf6e4 | ||
![]() |
77258b5e62 | ||
![]() |
dc7996922b | ||
![]() |
31a6ae00b5 | ||
![]() |
d2569c0f1e | ||
![]() |
ae9a48ebbb | ||
![]() |
1c00e0b9c1 | ||
![]() |
d8f786cfdf | ||
![]() |
75ef572a24 | ||
![]() |
f0f30224d3 | ||
![]() |
ec6e61e688 | ||
![]() |
3dd457c471 | ||
![]() |
3b8a34c8d0 | ||
![]() |
864709b006 | ||
![]() |
fe76955f3e | ||
![]() |
db8767fb05 | ||
![]() |
7dad9c2ab0 | ||
![]() |
4c0c0954a4 | ||
![]() |
f5a486a7da | ||
![]() |
a0b4100ff0 | ||
![]() |
425d57ba7d | ||
![]() |
1965a41725 | ||
![]() |
27f352b7dc | ||
![]() |
e01fb0b677 | ||
![]() |
671f0d62c7 | ||
![]() |
f1b888b309 | ||
![]() |
9cbcd0497a | ||
![]() |
0139de37ba | ||
![]() |
4e7fe88da3 | ||
![]() |
b1a81b45ea | ||
![]() |
fb0a8b9f3e | ||
![]() |
87ad8eab62 | ||
![]() |
6af4961695 | ||
![]() |
ae78f7798f | ||
![]() |
53295fde7e | ||
![]() |
268816bf7f | ||
![]() |
200bec8440 | ||
![]() |
df461c08a9 | ||
![]() |
bbf9dcc15a | ||
![]() |
a3e7105cb0 | ||
![]() |
10e5400d1f | ||
![]() |
97eb949670 | ||
![]() |
8f484a89f3 | ||
![]() |
1f35c35e2a | ||
![]() |
427560f814 | ||
![]() |
991200551d | ||
![]() |
60de0c6e69 | ||
![]() |
4a3000bcc5 | ||
![]() |
25cac3e04e | ||
![]() |
fc386a2648 | ||
![]() |
3fd9a3507c | ||
![]() |
d92005113a | ||
![]() |
fb2d764c89 | ||
![]() |
0251bb48ec | ||
![]() |
a035db1d11 | ||
![]() |
88049f9801 | ||
![]() |
42a9125ea7 | ||
![]() |
63972ff272 | ||
![]() |
dc53473e7e | ||
![]() |
2c290e3bee | ||
![]() |
c37494ea55 | ||
![]() |
b3e8963a33 | ||
![]() |
e2c77c0c4f | ||
![]() |
139ce4c655 | ||
![]() |
010dc35efc | ||
![]() |
413969300b | ||
![]() |
b67a88027d | ||
![]() |
2384b54ee3 | ||
![]() |
c3ae23dc90 | ||
![]() |
aa00091e2b | ||
![]() |
7e3a203f0b | ||
![]() |
054e39316c | ||
![]() |
7ce879521d | ||
![]() |
6f5f378857 | ||
![]() |
773950332b | ||
![]() |
35cd8616a2 | ||
![]() |
95786ce269 | ||
![]() |
c082ee616e | ||
![]() |
869f96f832 | ||
![]() |
2dff08b6f9 | ||
![]() |
e76c40a1e7 | ||
![]() |
504ca09451 | ||
![]() |
90c4b71d3f | ||
![]() |
7e1db7a75c | ||
![]() |
2f298992cf | ||
![]() |
c8c5c26896 | ||
![]() |
d8545ef946 | ||
![]() |
db68f9571b | ||
![]() |
0350471fa9 | ||
![]() |
3ed533d709 | ||
![]() |
e472a345c9 | ||
![]() |
42be5d892a | ||
![]() |
9a0d5019e1 | ||
![]() |
fc8c1ac9dd | ||
![]() |
536134e2b5 | ||
![]() |
005d4354d5 | ||
![]() |
7107b5cfef | ||
![]() |
bb153d42dc | ||
![]() |
a3806e4de2 | ||
![]() |
4dbe19a56e | ||
![]() |
0b74122d6f | ||
![]() |
e148c22f25 | ||
![]() |
33fb4d5d42 | ||
![]() |
7f7623cc8d | ||
![]() |
f2e914fb94 | ||
![]() |
1678eb0591 | ||
![]() |
1a0943c960 | ||
![]() |
073590124d | ||
![]() |
dfa4328604 | ||
![]() |
9dab840c58 | ||
![]() |
29fff967f5 | ||
![]() |
2a35c95718 | ||
![]() |
4a70aa26e8 | ||
![]() |
748604d374 | ||
![]() |
d32db20aa0 | ||
![]() |
ae346bb94e | ||
![]() |
cb67010574 | ||
![]() |
defa452aa1 | ||
![]() |
97a476b475 | ||
![]() |
07a4f6f53c | ||
![]() |
7d2726ab21 | ||
![]() |
3862e3b4e7 | ||
![]() |
be84f12100 | ||
![]() |
0097a55eaa | ||
![]() |
d1609de25a | ||
![]() |
02395c92a1 | ||
![]() |
f2ac6b0af6 | ||
![]() |
a3c8f667a7 | ||
![]() |
d06bab01ac | ||
![]() |
591786a787 | ||
![]() |
6c593fde22 | ||
![]() |
5e862412d8 | ||
![]() |
c72489b502 | ||
![]() |
33f6599320 | ||
![]() |
5de7b874b0 | ||
![]() |
a27f6c72b9 | ||
![]() |
a80d3012bd | ||
![]() |
1c0a646309 | ||
![]() |
eabb781e5f | ||
![]() |
03c2cda17c | ||
![]() |
26b72ccb10 | ||
![]() |
ab993c6d5a | ||
![]() |
999090fa18 | ||
![]() |
2eed309224 | ||
![]() |
12980847a8 | ||
![]() |
01a6b38b89 | ||
![]() |
73b786c22e | ||
![]() |
c1a6e82322 | ||
![]() |
ec848bc7b4 | ||
![]() |
e5df43b934 | ||
![]() |
d13f87e891 | ||
![]() |
132d56fe1a | ||
![]() |
171e19381f | ||
![]() |
9cc7b060c9 | ||
![]() |
d178e2da6f | ||
![]() |
1e8f961362 | ||
![]() |
166f77610f | ||
![]() |
97dc244d1e | ||
![]() |
085ddebf7d | ||
![]() |
bccc3d79d8 | ||
![]() |
4df3bfe85d | ||
![]() |
99345574e4 | ||
![]() |
80c66b0742 | ||
![]() |
17d820570b | ||
![]() |
c979d5c9b1 | ||
![]() |
62c7f14d9a | ||
![]() |
13ac6df1dd | ||
![]() |
98d091fbc3 | ||
![]() |
22e67f9754 | ||
![]() |
515a97de76 | ||
![]() |
68b5337ed3 | ||
![]() |
8ee86c717b | ||
![]() |
10530cdef3 | ||
![]() |
5de0f9efc9 | ||
![]() |
6d1d7f137f | ||
![]() |
38e16efa11 | ||
![]() |
5e2f0f7f5e | ||
![]() |
83c7afc46f | ||
![]() |
10753f0f99 | ||
![]() |
34a852d433 | ||
![]() |
3922fbdef7 | ||
![]() |
e5415abf20 | ||
![]() |
67e1a92cce | ||
![]() |
4c64511a15 | ||
![]() |
75f3e0900e | ||
![]() |
abd33c21bf | ||
![]() |
d592ba2c5e | ||
![]() |
321eba5184 | ||
![]() |
82b9ec53fd | ||
![]() |
b9262f967b | ||
![]() |
949fb9a890 | ||
![]() |
99952a701f | ||
![]() |
88878adb6c | ||
![]() |
17e3b49ebb | ||
![]() |
a217747f5d | ||
![]() |
790c9cbb84 | ||
![]() |
da5fb6e24f | ||
![]() |
a77439b4b7 | ||
![]() |
1a049bdcbb | ||
![]() |
79686239d3 | ||
![]() |
c934e84e21 | ||
![]() |
5e2f8cb018 | ||
![]() |
6bd0af6d85 | ||
![]() |
0f28a49822 | ||
![]() |
66d96646b1 | ||
![]() |
be4cf6505f | ||
![]() |
e8ea7825a9 | ||
![]() |
8c13eab731 | ||
![]() |
bf4cbb0aee | ||
![]() |
aaec4b7bd3 | ||
![]() |
7bddcd4f64 | ||
![]() |
af205a5267 | ||
![]() |
c2599d7719 | ||
![]() |
4ea6f23d9e | ||
![]() |
f23fd52a26 | ||
![]() |
cfd43c81fb | ||
![]() |
3dcba675b4 | ||
![]() |
bb51031ec6 | ||
![]() |
ecb99cbcce | ||
![]() |
0a514821c6 | ||
![]() |
074fbb522c | ||
![]() |
71d6ba242e | ||
![]() |
37ffd64b48 | ||
![]() |
ec65652567 | ||
![]() |
731613421d | ||
![]() |
58dfad4ed0 | ||
![]() |
7eb029f4b9 | ||
![]() |
8da8d938f0 | ||
![]() |
64ac0d2bde | ||
![]() |
7d3cdd15ad | ||
![]() |
53baf02087 | ||
![]() |
a0d2392344 | ||
![]() |
fb3c092eaa | ||
![]() |
c169cf1e77 | ||
![]() |
fa4d8e083a | ||
![]() |
2cfeccfd71 | ||
![]() |
f36ca93752 | ||
![]() |
dc8714c277 | ||
![]() |
90fcb5fbcd | ||
![]() |
932d0a5d8b | ||
![]() |
4cafa18fa4 | ||
![]() |
b12d7db5a7 | ||
![]() |
e84345594d | ||
![]() |
add7bec7f2 | ||
![]() |
db84d8e8dc | ||
![]() |
ad51e647af | ||
![]() |
c45901746b | ||
![]() |
033c469250 | ||
![]() |
0900fd3cea | ||
![]() |
ba8f3d3f63 | ||
![]() |
2759f3828e | ||
![]() |
f395767766 | ||
![]() |
2dc222aea6 | ||
![]() |
82d68c87e2 | ||
![]() |
f213657753 | ||
![]() |
e077e6cec7 | ||
![]() |
339a3270f6 | ||
![]() |
462b44ee23 | ||
![]() |
52d3dba89c | ||
![]() |
939d01dd99 | ||
![]() |
4900f7c7ca | ||
![]() |
48957aee8b | ||
![]() |
e355ce04f7 | ||
![]() |
758e5b89bb | ||
![]() |
3ffdd1d451 | ||
![]() |
4c1b8c8b96 | ||
![]() |
3ca956cd6a | ||
![]() |
2e24a11a1d | ||
![]() |
10a03ad538 | ||
![]() |
69839ec4dc | ||
![]() |
28a66d4bf0 | ||
![]() |
782d894801 | ||
![]() |
06dd731c78 | ||
![]() |
6af74302dc | ||
![]() |
03380a6ecd | ||
![]() |
8d8db11dd9 | ||
![]() |
28886a896b | ||
![]() |
05253991c2 | ||
![]() |
96f0fda477 | ||
![]() |
023fa4d220 | ||
![]() |
a1f63c0dfc | ||
![]() |
ef98f42e7e | ||
![]() |
737e1284af | ||
![]() |
8677918157 | ||
![]() |
629c891dfc | ||
![]() |
8e8ef83780 | ||
![]() |
2a15f35e9d | ||
![]() |
9bfa942cf2 | ||
![]() |
b00adbddce | ||
![]() |
a71030c4de | ||
![]() |
6bb32c2e61 | ||
![]() |
7bc2c685e0 | ||
![]() |
9205338cc8 | ||
![]() |
04336f7ba3 | ||
![]() |
6f64312d08 | ||
![]() |
79dfb86830 | ||
![]() |
453dc29540 | ||
![]() |
f4260d370c | ||
![]() |
655f9489a8 | ||
![]() |
4b3cc52afe | ||
![]() |
fd3f15637a | ||
![]() |
1311e1b8b0 | ||
![]() |
64e84872da | ||
![]() |
bc7379030e | ||
![]() |
ecfb6dc8ed | ||
![]() |
75d67af932 | ||
![]() |
845dad6ee7 | ||
![]() |
e2e86da64b | ||
![]() |
90ec63589f | ||
![]() |
ea308eaaa2 | ||
![]() |
87f1fac2bf | ||
![]() |
c23651527f | ||
![]() |
2cc263a707 | ||
![]() |
fb336718de | ||
![]() |
e2e35bf965 | ||
![]() |
bdd25c7268 | ||
![]() |
82c788d6ce | ||
![]() |
5167184cc7 | ||
![]() |
a5d1b11204 | ||
![]() |
dc8f2fd37e | ||
![]() |
7c85886ce8 | ||
![]() |
12f172436d | ||
![]() |
e69ac0478e | ||
![]() |
a45743c2b7 | ||
![]() |
ebe1531927 | ||
![]() |
a88a059c6a | ||
![]() |
d314cbb0d5 | ||
![]() |
4d75758eb2 | ||
![]() |
0eecc29039 | ||
![]() |
294fb67410 | ||
![]() |
2f1f098b47 | ||
![]() |
77be414261 | ||
![]() |
c34fc3c4c7 | ||
![]() |
8aac2f525e | ||
![]() |
f85dcdca4e | ||
![]() |
e7a1ef7aa1 | ||
![]() |
7c2d2ef5a3 | ||
![]() |
1449001747 | ||
![]() |
f245c74520 | ||
![]() |
da1658e4f9 | ||
![]() |
80f9352a79 | ||
![]() |
9ded501402 | ||
![]() |
3d6a1811c5 | ||
![]() |
a5ee047efb | ||
![]() |
fb0090dcdc | ||
![]() |
294bd4d042 | ||
![]() |
e99b8d2daf | ||
![]() |
6dbdeeb59b | ||
![]() |
82fd62e9dd | ||
![]() |
70f935d323 | ||
![]() |
0f3e6cccd9 | ||
![]() |
6ff323c56d | ||
![]() |
096ec79ef9 | ||
![]() |
bf5ba65558 | ||
![]() |
62088dfaed | ||
![]() |
dfcc3206f7 | ||
![]() |
e173b7f0c2 | ||
![]() |
f98e28a8a2 | ||
![]() |
f63557f2e7 | ||
![]() |
a353598961 | ||
![]() |
bc33b44648 | ||
![]() |
1579779967 | ||
![]() |
cc6ea4cd14 | ||
![]() |
303a8ff87a | ||
![]() |
7d3a11a735 | ||
![]() |
94b6344820 | ||
![]() |
40307c079c | ||
![]() |
debef6fde4 | ||
![]() |
0cda83d29c | ||
![]() |
32729c7ca7 | ||
![]() |
b7fca5488a | ||
![]() |
9c22772758 | ||
![]() |
1e72f07fdf | ||
![]() |
a592e96709 | ||
![]() |
3980339868 | ||
![]() |
afa66c17bd | ||
![]() |
be2988b1d7 | ||
![]() |
cf647f0c36 | ||
![]() |
385ed4ca0c | ||
![]() |
9188a8e326 | ||
![]() |
0efb6d55c8 | ||
![]() |
f748047b7b | ||
![]() |
49bc767bf4 | ||
![]() |
e12cc9a9a7 | ||
![]() |
8e4470cdff | ||
![]() |
bdb7e19fd0 | ||
![]() |
0fc3f0e162 | ||
![]() |
6fac66e63b | ||
![]() |
71e06ea1b6 | ||
![]() |
3df434fd55 | ||
![]() |
729b2b2873 | ||
![]() |
bc2adb6b5a | ||
![]() |
aaff086aeb | ||
![]() |
e4c0f18ee3 | ||
![]() |
9c09a271f2 | ||
![]() |
37578f3e22 | ||
![]() |
4649599592 | ||
![]() |
71f78e3a81 | ||
![]() |
f7ca26eef8 | ||
![]() |
0665fcea9e | ||
![]() |
cd2b50c27f | ||
![]() |
ca70f17b3b | ||
![]() |
a5e08aaf74 | ||
![]() |
947db4605a | ||
![]() |
481a00a0b5 | ||
![]() |
465019e510 | ||
![]() |
a4d5f39fb6 | ||
![]() |
5dd76966c3 | ||
![]() |
db86f87fc3 | ||
![]() |
e21334b7fa | ||
![]() |
ba4c268956 | ||
![]() |
068594be5e | ||
![]() |
0fd45fc86e | ||
![]() |
257fb98113 | ||
![]() |
f8922b3cca | ||
![]() |
b0b08f317b | ||
![]() |
a8e4ed009b | ||
![]() |
2c4667fb46 | ||
![]() |
9eadfa21d8 | ||
![]() |
953fd24458 | ||
![]() |
1be171e084 | ||
![]() |
5c83b99e0c | ||
![]() |
743e611735 | ||
![]() |
35ff850894 | ||
![]() |
b666295b53 | ||
![]() |
96cf8d97ab | ||
![]() |
3c1a781a1c | ||
![]() |
00bd1b0a02 | ||
![]() |
b8482da421 | ||
![]() |
756ece9ff3 | ||
![]() |
4bb016fec3 | ||
![]() |
32f0322dec | ||
![]() |
1a1c13b722 | ||
![]() |
139453822b | ||
![]() |
7a33994666 | ||
![]() |
f381d9011b | ||
![]() |
96352f047d | ||
![]() |
5e7a1fea8c | ||
![]() |
baaafb7fcb | ||
![]() |
64eb70444d | ||
![]() |
0f39b1c49a | ||
![]() |
e2d6363c68 | ||
![]() |
cdeef700c2 | ||
![]() |
86fd702841 | ||
![]() |
b1553807f7 | ||
![]() |
797d4929ab | ||
![]() |
ba5bb9dfa7 | ||
![]() |
dd49d832c4 | ||
![]() |
5004f44f65 | ||
![]() |
bc9c4a8b8e | ||
![]() |
6f05ee7427 | ||
![]() |
f3523a96c9 | ||
![]() |
06957d9895 | ||
![]() |
1f361b07d1 | ||
![]() |
40d9c0a3db | ||
![]() |
548cd39496 | ||
![]() |
85049611c3 | ||
![]() |
b8a75bc925 | ||
![]() |
6c62d4a923 | ||
![]() |
6e42d009fb | ||
![]() |
7d7769ea5d | ||
![]() |
3908677fe2 | ||
![]() |
9799a2b636 | ||
![]() |
55c8129423 | ||
![]() |
099474053e | ||
![]() |
efafabed97 | ||
![]() |
d209739f85 | ||
![]() |
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 | ||
![]() |
60cc4c4ed0 | ||
![]() |
34c100e997 | ||
![]() |
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 |
@@ -168,8 +168,6 @@ This document provides essential context for AI models interacting with this pro
|
||||
* `platformio.ini`: Configures the PlatformIO build environments for different microcontrollers.
|
||||
* `.pre-commit-config.yaml`: Configures the pre-commit hooks for linting and formatting.
|
||||
* **CI/CD Pipeline:** Defined in `.github/workflows`.
|
||||
* **Static Analysis & Development:**
|
||||
* `esphome/core/defines.h`: A comprehensive header file containing all `#define` directives that can be added by components using `cg.add_define()` in Python. This file is used exclusively for development, static analysis tools, and CI testing - it is not used during runtime compilation. When developing components that add new defines, they must be added to this file to ensure proper IDE support and static analysis coverage. The file includes feature flags, build configurations, and platform-specific defines that help static analyzers understand the complete codebase without needing to compile for specific platforms.
|
||||
|
||||
## 6. Development & Testing Workflow
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
6af8b429b94191fe8e239fcb3b73f7982d0266cb5b05ffbc81edaeac1bc8c273
|
||||
7920671c938a5ea6a11ac4594204b5ec8f38d579c962bf1f185e8d5e3ad879be
|
||||
|
2
.github/actions/restore-python/action.yml
vendored
2
.github/actions/restore-python/action.yml
vendored
@@ -22,7 +22,7 @@ runs:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.4
|
||||
uses: actions/cache/restore@v4.2.3
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
|
923
.github/workflows/auto-label-pr.yml
vendored
923
.github/workflows/auto-label-pr.yml
vendored
File diff suppressed because it is too large
Load Diff
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.4
|
||||
uses: actions/cache@v4.2.3
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Save Python virtual environment cache
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache/save@v4.2.4
|
||||
uses: actions/cache/save@v4.2.3
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
python-version: "3.13"
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.4
|
||||
uses: actions/cache@v4.2.3
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
|
||||
@@ -281,7 +281,7 @@ jobs:
|
||||
pio_cache_key: tidyesp32-idf
|
||||
- id: clang-tidy
|
||||
name: Run script/clang-tidy for ZEPHYR
|
||||
options: --environment nrf52-tidy --grep USE_ZEPHYR --grep USE_NRF52
|
||||
options: --environment nrf52-tidy --grep USE_ZEPHYR
|
||||
pio_cache_key: tidy-zephyr
|
||||
ignore_errors: false
|
||||
|
||||
@@ -300,14 +300,14 @@ jobs:
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache@v4.2.4
|
||||
uses: actions/cache@v4.2.3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref != 'refs/heads/dev'
|
||||
uses: actions/cache/restore@v4.2.4
|
||||
uses: actions/cache/restore@v4.2.3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -102,12 +102,12 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3.11.1
|
||||
|
||||
- name: Log in to docker hub
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.4.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the GitHub container registry
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v5.0.0
|
||||
uses: actions/download-artifact@v4.3.0
|
||||
with:
|
||||
pattern: digests-*
|
||||
path: /tmp/digests
|
||||
@@ -182,13 +182,13 @@ jobs:
|
||||
|
||||
- name: Log in to docker hub
|
||||
if: matrix.registry == 'dockerhub'
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.4.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the GitHub container registry
|
||||
if: matrix.registry == 'ghcr'
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
@@ -11,7 +11,7 @@ ci:
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.12.8
|
||||
rev: v0.12.4
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
|
26
CODEOWNERS
26
CODEOWNERS
@@ -40,11 +40,11 @@ esphome/components/analog_threshold/* @ianchi
|
||||
esphome/components/animation/* @syndlex
|
||||
esphome/components/anova/* @buxtronix
|
||||
esphome/components/apds9306/* @aodrenah
|
||||
esphome/components/api/* @esphome/core
|
||||
esphome/components/api/* @OttoWinter
|
||||
esphome/components/as5600/* @ammmze
|
||||
esphome/components/as5600/sensor/* @ammmze
|
||||
esphome/components/as7341/* @mrgnr
|
||||
esphome/components/async_tcp/* @esphome/core
|
||||
esphome/components/async_tcp/* @OttoWinter
|
||||
esphome/components/at581x/* @X-Ryl669
|
||||
esphome/components/atc_mithermometer/* @ahpohl
|
||||
esphome/components/atm90e26/* @danieltwagner
|
||||
@@ -69,7 +69,7 @@ esphome/components/bl0939/* @ziceva
|
||||
esphome/components/bl0940/* @tobias-
|
||||
esphome/components/bl0942/* @dbuezas @dwmw2
|
||||
esphome/components/ble_client/* @buxtronix @clydebarrow
|
||||
esphome/components/bluetooth_proxy/* @bdraco @jesserockz
|
||||
esphome/components/bluetooth_proxy/* @jesserockz
|
||||
esphome/components/bme280_base/* @esphome/core
|
||||
esphome/components/bme280_spi/* @apbodrov
|
||||
esphome/components/bme680_bsec/* @trvrnrth
|
||||
@@ -91,7 +91,7 @@ esphome/components/bytebuffer/* @clydebarrow
|
||||
esphome/components/camera/* @DT-art1 @bdraco
|
||||
esphome/components/canbus/* @danielschramm @mvturnho
|
||||
esphome/components/cap1188/* @mreditor97
|
||||
esphome/components/captive_portal/* @esphome/core
|
||||
esphome/components/captive_portal/* @OttoWinter
|
||||
esphome/components/ccs811/* @habbie
|
||||
esphome/components/cd74hc4067/* @asoehlke
|
||||
esphome/components/ch422g/* @clydebarrow @jesterret
|
||||
@@ -118,7 +118,7 @@ esphome/components/dallas_temp/* @ssieb
|
||||
esphome/components/daly_bms/* @s1lvi0
|
||||
esphome/components/dashboard_import/* @esphome/core
|
||||
esphome/components/datetime/* @jesserockz @rfdarter
|
||||
esphome/components/debug/* @esphome/core
|
||||
esphome/components/debug/* @OttoWinter
|
||||
esphome/components/delonghi/* @grob6000
|
||||
esphome/components/dfplayer/* @glmnet
|
||||
esphome/components/dfrobot_sen0395/* @niklasweber
|
||||
@@ -144,10 +144,9 @@ esphome/components/es8156/* @kbx81
|
||||
esphome/components/es8311/* @kahrendt @kroimon
|
||||
esphome/components/es8388/* @P4uLT
|
||||
esphome/components/esp32/* @esphome/core
|
||||
esphome/components/esp32_ble/* @Rapsssito @bdraco @jesserockz
|
||||
esphome/components/esp32_ble_client/* @bdraco @jesserockz
|
||||
esphome/components/esp32_ble/* @Rapsssito @jesserockz
|
||||
esphome/components/esp32_ble_client/* @jesserockz
|
||||
esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
|
||||
esphome/components/esp32_ble_tracker/* @bdraco
|
||||
esphome/components/esp32_camera_web_server/* @ayufan
|
||||
esphome/components/esp32_can/* @Sympatron
|
||||
esphome/components/esp32_hosted/* @swoboda1337
|
||||
@@ -156,7 +155,6 @@ esphome/components/esp32_rmt/* @jesserockz
|
||||
esphome/components/esp32_rmt_led_strip/* @jesserockz
|
||||
esphome/components/esp8266/* @esphome/core
|
||||
esphome/components/esp_ldo/* @clydebarrow
|
||||
esphome/components/espnow/* @jesserockz
|
||||
esphome/components/ethernet_info/* @gtjadsonsantos
|
||||
esphome/components/event/* @nohat
|
||||
esphome/components/event_emitter/* @Rapsssito
|
||||
@@ -238,7 +236,7 @@ esphome/components/integration/* @OttoWinter
|
||||
esphome/components/internal_temperature/* @Mat931
|
||||
esphome/components/interval/* @esphome/core
|
||||
esphome/components/jsn_sr04t/* @Mafus1
|
||||
esphome/components/json/* @esphome/core
|
||||
esphome/components/json/* @OttoWinter
|
||||
esphome/components/kamstrup_kmp/* @cfeenstra1024
|
||||
esphome/components/key_collector/* @ssieb
|
||||
esphome/components/key_provider/* @ssieb
|
||||
@@ -248,7 +246,6 @@ esphome/components/lcd_menu/* @numo68
|
||||
esphome/components/ld2410/* @regevbr @sebcaps
|
||||
esphome/components/ld2420/* @descipher
|
||||
esphome/components/ld2450/* @hareeshmu
|
||||
esphome/components/ld24xx/* @kbx81
|
||||
esphome/components/ledc/* @OttoWinter
|
||||
esphome/components/libretiny/* @kuba2k2
|
||||
esphome/components/libretiny_pwm/* @kuba2k2
|
||||
@@ -296,7 +293,6 @@ esphome/components/microphone/* @jesserockz @kahrendt
|
||||
esphome/components/mics_4514/* @jesserockz
|
||||
esphome/components/midea/* @dudanov
|
||||
esphome/components/midea_ir/* @dudanov
|
||||
esphome/components/mipi_dsi/* @clydebarrow
|
||||
esphome/components/mipi_spi/* @clydebarrow
|
||||
esphome/components/mitsubishi/* @RubyBailey
|
||||
esphome/components/mixer/speaker/* @kahrendt
|
||||
@@ -468,13 +464,13 @@ esphome/components/template/event/* @nohat
|
||||
esphome/components/template/fan/* @ssieb
|
||||
esphome/components/text/* @mauritskorse
|
||||
esphome/components/thermostat/* @kbx81
|
||||
esphome/components/time/* @esphome/core
|
||||
esphome/components/time/* @OttoWinter
|
||||
esphome/components/tlc5947/* @rnauber
|
||||
esphome/components/tlc5971/* @IJIJI
|
||||
esphome/components/tm1621/* @Philippe12
|
||||
esphome/components/tm1637/* @glmnet
|
||||
esphome/components/tm1638/* @skykingjwc
|
||||
esphome/components/tm1651/* @mrtoy-me
|
||||
esphome/components/tm1651/* @freekode
|
||||
esphome/components/tmp102/* @timsavage
|
||||
esphome/components/tmp1075/* @sybrenstuvel
|
||||
esphome/components/tmp117/* @Azimath
|
||||
@@ -512,7 +508,7 @@ esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
|
||||
esphome/components/watchdog/* @oarcher
|
||||
esphome/components/waveshare_epaper/* @clydebarrow
|
||||
esphome/components/web_server/ota/* @esphome/core
|
||||
esphome/components/web_server_base/* @esphome/core
|
||||
esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/web_server_idf/* @dentra
|
||||
esphome/components/weikai/* @DrCoolZic
|
||||
esphome/components/weikai_i2c/* @DrCoolZic
|
||||
|
@@ -2,14 +2,12 @@
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import functools
|
||||
import getpass
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from typing import Protocol
|
||||
|
||||
import argcomplete
|
||||
|
||||
@@ -45,7 +43,6 @@ from esphome.const import (
|
||||
from esphome.core import CORE, EsphomeError, coroutine
|
||||
from esphome.helpers import get_bool_env, indent, is_ip_address
|
||||
from esphome.log import AnsiFore, color, setup_log
|
||||
from esphome.types import ConfigType
|
||||
from esphome.util import (
|
||||
get_serial_ports,
|
||||
list_yaml_files,
|
||||
@@ -57,23 +54,6 @@ from esphome.util import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ArgsProtocol(Protocol):
|
||||
device: list[str] | None
|
||||
reset: bool
|
||||
username: str | None
|
||||
password: str | None
|
||||
client_id: str | None
|
||||
topic: str | None
|
||||
file: str | None
|
||||
no_logs: bool
|
||||
only_generate: bool
|
||||
show_secrets: bool
|
||||
dashboard: bool
|
||||
configuration: str
|
||||
name: str
|
||||
upload_speed: str | None
|
||||
|
||||
|
||||
def choose_prompt(options, purpose: str = None):
|
||||
if not options:
|
||||
raise EsphomeError(
|
||||
@@ -107,54 +87,30 @@ def choose_prompt(options, purpose: str = None):
|
||||
|
||||
|
||||
def choose_upload_log_host(
|
||||
default: list[str] | str | None,
|
||||
check_default: str | None,
|
||||
show_ota: bool,
|
||||
show_mqtt: bool,
|
||||
show_api: bool,
|
||||
purpose: str | None = None,
|
||||
) -> list[str]:
|
||||
# Convert to list for uniform handling
|
||||
defaults = [default] if isinstance(default, str) else default or []
|
||||
|
||||
# If devices specified, resolve them
|
||||
if defaults:
|
||||
resolved: list[str] = []
|
||||
for device in defaults:
|
||||
if device == "SERIAL":
|
||||
serial_ports = get_serial_ports()
|
||||
if not serial_ports:
|
||||
_LOGGER.warning("No serial ports found, skipping SERIAL device")
|
||||
continue
|
||||
options = [
|
||||
(f"{port.path} ({port.description})", port.path)
|
||||
for port in serial_ports
|
||||
]
|
||||
resolved.append(choose_prompt(options, purpose=purpose))
|
||||
elif device == "OTA":
|
||||
if (show_ota and "ota" in CORE.config) or (
|
||||
show_api and "api" in CORE.config
|
||||
):
|
||||
resolved.append(CORE.address)
|
||||
elif show_mqtt and has_mqtt_logging():
|
||||
resolved.append("MQTT")
|
||||
else:
|
||||
resolved.append(device)
|
||||
return resolved
|
||||
|
||||
# No devices specified, show interactive chooser
|
||||
options = [
|
||||
(f"{port.path} ({port.description})", port.path) for port in get_serial_ports()
|
||||
]
|
||||
default, check_default, show_ota, show_mqtt, show_api, purpose: str = None
|
||||
):
|
||||
options = []
|
||||
for port in get_serial_ports():
|
||||
options.append((f"{port.path} ({port.description})", port.path))
|
||||
if default == "SERIAL":
|
||||
return choose_prompt(options, purpose=purpose)
|
||||
if (show_ota and "ota" in CORE.config) or (show_api and "api" in CORE.config):
|
||||
options.append((f"Over The Air ({CORE.address})", CORE.address))
|
||||
if show_mqtt and has_mqtt_logging():
|
||||
mqtt_config = CORE.config[CONF_MQTT]
|
||||
if default == "OTA":
|
||||
return CORE.address
|
||||
if (
|
||||
show_mqtt
|
||||
and (mqtt_config := CORE.config.get(CONF_MQTT))
|
||||
and mqtt_logging_enabled(mqtt_config)
|
||||
):
|
||||
options.append((f"MQTT ({mqtt_config[CONF_BROKER]})", "MQTT"))
|
||||
|
||||
if default == "OTA":
|
||||
return "MQTT"
|
||||
if default is not None:
|
||||
return default
|
||||
if check_default is not None and check_default in [opt[1] for opt in options]:
|
||||
return [check_default]
|
||||
return [choose_prompt(options, purpose=purpose)]
|
||||
return check_default
|
||||
return choose_prompt(options, purpose=purpose)
|
||||
|
||||
|
||||
def mqtt_logging_enabled(mqtt_config):
|
||||
@@ -163,17 +119,12 @@ def mqtt_logging_enabled(mqtt_config):
|
||||
return False
|
||||
if CONF_TOPIC not in log_topic:
|
||||
return False
|
||||
return log_topic.get(CONF_LEVEL, None) != "NONE"
|
||||
if log_topic.get(CONF_LEVEL, None) == "NONE":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def has_mqtt_logging() -> bool:
|
||||
"""Check if MQTT logging is available."""
|
||||
return (mqtt_config := CORE.config.get(CONF_MQTT)) and mqtt_logging_enabled(
|
||||
mqtt_config
|
||||
)
|
||||
|
||||
|
||||
def get_port_type(port: str) -> str:
|
||||
def get_port_type(port):
|
||||
if port.startswith("/") or port.startswith("COM"):
|
||||
return "SERIAL"
|
||||
if port == "MQTT":
|
||||
@@ -181,7 +132,7 @@ def get_port_type(port: str) -> str:
|
||||
return "NETWORK"
|
||||
|
||||
|
||||
def run_miniterm(config: ConfigType, port: str, args) -> int:
|
||||
def run_miniterm(config, port, args):
|
||||
from aioesphomeapi import LogParser
|
||||
import serial
|
||||
|
||||
@@ -258,7 +209,7 @@ def wrap_to_code(name, comp):
|
||||
return wrapped
|
||||
|
||||
|
||||
def write_cpp(config: ConfigType) -> int:
|
||||
def write_cpp(config):
|
||||
if not get_bool_env(ENV_NOGITIGNORE):
|
||||
writer.write_gitignore()
|
||||
|
||||
@@ -266,7 +217,7 @@ def write_cpp(config: ConfigType) -> int:
|
||||
return write_cpp_file()
|
||||
|
||||
|
||||
def generate_cpp_contents(config: ConfigType) -> None:
|
||||
def generate_cpp_contents(config):
|
||||
_LOGGER.info("Generating C++ source...")
|
||||
|
||||
for name, component, conf in iter_component_configs(CORE.config):
|
||||
@@ -277,7 +228,7 @@ def generate_cpp_contents(config: ConfigType) -> None:
|
||||
CORE.flush_tasks()
|
||||
|
||||
|
||||
def write_cpp_file() -> int:
|
||||
def write_cpp_file():
|
||||
code_s = indent(CORE.cpp_main_section)
|
||||
writer.write_cpp(code_s)
|
||||
|
||||
@@ -288,7 +239,7 @@ def write_cpp_file() -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
def compile_program(args, config):
|
||||
from esphome import platformio_api
|
||||
|
||||
_LOGGER.info("Compiling app...")
|
||||
@@ -299,9 +250,7 @@ def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
return 0 if idedata is not None else 1
|
||||
|
||||
|
||||
def upload_using_esptool(
|
||||
config: ConfigType, port: str, file: str, speed: int
|
||||
) -> str | int:
|
||||
def upload_using_esptool(config, port, file, speed):
|
||||
from esphome import platformio_api
|
||||
|
||||
first_baudrate = speed or config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get(
|
||||
@@ -329,20 +278,20 @@ def upload_using_esptool(
|
||||
|
||||
def run_esptool(baud_rate):
|
||||
cmd = [
|
||||
"esptool",
|
||||
"esptool.py",
|
||||
"--before",
|
||||
"default-reset",
|
||||
"default_reset",
|
||||
"--after",
|
||||
"hard-reset",
|
||||
"hard_reset",
|
||||
"--baud",
|
||||
str(baud_rate),
|
||||
"--port",
|
||||
port,
|
||||
"--chip",
|
||||
mcu,
|
||||
"write-flash",
|
||||
"write_flash",
|
||||
"-z",
|
||||
"--flash-size",
|
||||
"--flash_size",
|
||||
"detect",
|
||||
]
|
||||
for img in flash_images:
|
||||
@@ -366,7 +315,7 @@ def upload_using_esptool(
|
||||
return run_esptool(115200)
|
||||
|
||||
|
||||
def upload_using_platformio(config: ConfigType, port: str):
|
||||
def upload_using_platformio(config, port):
|
||||
from esphome import platformio_api
|
||||
|
||||
upload_args = ["-t", "upload", "-t", "nobuild"]
|
||||
@@ -375,7 +324,7 @@ def upload_using_platformio(config: ConfigType, port: str):
|
||||
return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
|
||||
|
||||
def check_permissions(port: str):
|
||||
def check_permissions(port):
|
||||
if os.name == "posix" and get_port_type(port) == "SERIAL":
|
||||
# Check if we can open selected serial port
|
||||
if not os.access(port, os.F_OK):
|
||||
@@ -388,12 +337,12 @@ def check_permissions(port: str):
|
||||
raise EsphomeError(
|
||||
"You do not have read or write permission on the selected serial port. "
|
||||
"To resolve this issue, you can add your user to the dialout group "
|
||||
f"by running the following command: sudo usermod -a -G dialout {getpass.getuser()}. "
|
||||
f"by running the following command: sudo usermod -a -G dialout {os.getlogin()}. "
|
||||
"You will need to log out & back in or reboot to activate the new group access."
|
||||
)
|
||||
|
||||
|
||||
def upload_program(config: ConfigType, args: ArgsProtocol, host: str) -> int | str:
|
||||
def upload_program(config, args, host):
|
||||
try:
|
||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||
if getattr(module, "upload_program")(config, args, host):
|
||||
@@ -408,7 +357,7 @@ def upload_program(config: ConfigType, args: ArgsProtocol, host: str) -> int | s
|
||||
return upload_using_esptool(config, host, file, args.upload_speed)
|
||||
|
||||
if CORE.target_platform in (PLATFORM_RP2040):
|
||||
return upload_using_platformio(config, host)
|
||||
return upload_using_platformio(config, args.device)
|
||||
|
||||
if CORE.is_libretiny:
|
||||
return upload_using_platformio(config, host)
|
||||
@@ -431,12 +380,9 @@ def upload_program(config: ConfigType, args: ArgsProtocol, host: str) -> int | s
|
||||
remote_port = int(ota_conf[CONF_PORT])
|
||||
password = ota_conf.get(CONF_PASSWORD, "")
|
||||
|
||||
# Check if we should use MQTT for address resolution
|
||||
# This happens when no device was specified, or the current host is "MQTT"/"OTA"
|
||||
devices: list[str] = args.device or []
|
||||
if (
|
||||
CONF_MQTT in config # pylint: disable=too-many-boolean-expressions
|
||||
and (not devices or host in ("MQTT", "OTA"))
|
||||
and (not args.device or args.device in ("MQTT", "OTA"))
|
||||
and (
|
||||
((config[CONF_MDNS][CONF_DISABLED]) and not is_ip_address(CORE.address))
|
||||
or get_port_type(host) == "MQTT"
|
||||
@@ -454,28 +400,23 @@ def upload_program(config: ConfigType, args: ArgsProtocol, host: str) -> int | s
|
||||
return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
|
||||
|
||||
|
||||
def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int | None:
|
||||
def show_logs(config, args, port):
|
||||
if "logger" not in config:
|
||||
raise EsphomeError("Logger is not configured!")
|
||||
|
||||
port = devices[0]
|
||||
|
||||
if get_port_type(port) == "SERIAL":
|
||||
check_permissions(port)
|
||||
return run_miniterm(config, port, args)
|
||||
if get_port_type(port) == "NETWORK" and "api" in config:
|
||||
addresses_to_use = devices
|
||||
if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
|
||||
from esphome import mqtt
|
||||
|
||||
mqtt_address = mqtt.get_esphome_device_ip(
|
||||
port = mqtt.get_esphome_device_ip(
|
||||
config, args.username, args.password, args.client_id
|
||||
)[0]
|
||||
addresses_to_use = [mqtt_address]
|
||||
|
||||
from esphome.components.api.client import run_logs
|
||||
|
||||
return run_logs(config, addresses_to_use)
|
||||
return run_logs(config, port)
|
||||
if get_port_type(port) == "MQTT" and "mqtt" in config:
|
||||
from esphome import mqtt
|
||||
|
||||
@@ -486,7 +427,7 @@ def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int
|
||||
raise EsphomeError("No remote or local logging method configured (api/mqtt/logger)")
|
||||
|
||||
|
||||
def clean_mqtt(config: ConfigType, args: ArgsProtocol) -> int | None:
|
||||
def clean_mqtt(config, args):
|
||||
from esphome import mqtt
|
||||
|
||||
return mqtt.clear_topic(
|
||||
@@ -494,13 +435,13 @@ def clean_mqtt(config: ConfigType, args: ArgsProtocol) -> int | None:
|
||||
)
|
||||
|
||||
|
||||
def command_wizard(args: ArgsProtocol) -> int | None:
|
||||
def command_wizard(args):
|
||||
from esphome import wizard
|
||||
|
||||
return wizard.wizard(args.configuration)
|
||||
|
||||
|
||||
def command_config(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_config(args, config):
|
||||
if not CORE.verbose:
|
||||
config = strip_default_ids(config)
|
||||
output = yaml_util.dump(config, args.show_secrets)
|
||||
@@ -515,7 +456,7 @@ def command_config(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return 0
|
||||
|
||||
|
||||
def command_vscode(args: ArgsProtocol) -> int | None:
|
||||
def command_vscode(args):
|
||||
from esphome import vscode
|
||||
|
||||
logging.disable(logging.INFO)
|
||||
@@ -523,7 +464,14 @@ def command_vscode(args: ArgsProtocol) -> int | None:
|
||||
vscode.read_config(args)
|
||||
|
||||
|
||||
def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_compile(args, config):
|
||||
# Set memory analysis options in config
|
||||
if args.analyze_memory:
|
||||
config.setdefault(CONF_ESPHOME, {})["analyze_memory"] = True
|
||||
|
||||
if args.memory_report:
|
||||
config.setdefault(CONF_ESPHOME, {})["memory_report_file"] = args.memory_report
|
||||
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
@@ -537,9 +485,8 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return 0
|
||||
|
||||
|
||||
def command_upload(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
# Get devices, resolving special identifiers like OTA
|
||||
devices = choose_upload_log_host(
|
||||
def command_upload(args, config):
|
||||
port = choose_upload_log_host(
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=True,
|
||||
@@ -547,22 +494,14 @@ def command_upload(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
show_api=False,
|
||||
purpose="uploading",
|
||||
)
|
||||
|
||||
# Try each device until one succeeds
|
||||
exit_code = 1
|
||||
for device in devices:
|
||||
_LOGGER.info("Uploading to %s", device)
|
||||
exit_code = upload_program(config, args, device)
|
||||
if exit_code == 0:
|
||||
_LOGGER.info("Successfully uploaded program.")
|
||||
return 0
|
||||
if len(devices) > 1:
|
||||
_LOGGER.warning("Failed to upload to %s", device)
|
||||
|
||||
return exit_code
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info("Successfully uploaded program.")
|
||||
return 0
|
||||
|
||||
|
||||
def command_discover(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_discover(args, config):
|
||||
if "mqtt" in config:
|
||||
from esphome import mqtt
|
||||
|
||||
@@ -571,9 +510,8 @@ def command_discover(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
raise EsphomeError("No discover method configured (mqtt)")
|
||||
|
||||
|
||||
def command_logs(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
# Get devices, resolving special identifiers like OTA
|
||||
devices = choose_upload_log_host(
|
||||
def command_logs(args, config):
|
||||
port = choose_upload_log_host(
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=False,
|
||||
@@ -581,10 +519,10 @@ def command_logs(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
show_api=True,
|
||||
purpose="logging",
|
||||
)
|
||||
return show_logs(config, args, devices)
|
||||
return show_logs(config, args, port)
|
||||
|
||||
|
||||
def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_run(args, config):
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
@@ -601,8 +539,7 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
program_path = idedata.raw["prog_path"]
|
||||
return run_external_process(program_path)
|
||||
|
||||
# Get devices, resolving special identifiers like OTA
|
||||
devices = choose_upload_log_host(
|
||||
port = choose_upload_log_host(
|
||||
default=args.device,
|
||||
check_default=None,
|
||||
show_ota=True,
|
||||
@@ -610,53 +547,39 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
show_api=True,
|
||||
purpose="uploading",
|
||||
)
|
||||
|
||||
# Try each device for upload until one succeeds
|
||||
successful_device: str | None = None
|
||||
for device in devices:
|
||||
_LOGGER.info("Uploading to %s", device)
|
||||
exit_code = upload_program(config, args, device)
|
||||
if exit_code == 0:
|
||||
_LOGGER.info("Successfully uploaded program.")
|
||||
successful_device = device
|
||||
break
|
||||
if len(devices) > 1:
|
||||
_LOGGER.warning("Failed to upload to %s", device)
|
||||
|
||||
if successful_device is None:
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
|
||||
_LOGGER.info("Successfully uploaded program.")
|
||||
if args.no_logs:
|
||||
return 0
|
||||
|
||||
# For logs, prefer the device we successfully uploaded to
|
||||
devices = choose_upload_log_host(
|
||||
default=successful_device,
|
||||
check_default=successful_device,
|
||||
port = choose_upload_log_host(
|
||||
default=args.device,
|
||||
check_default=port,
|
||||
show_ota=False,
|
||||
show_mqtt=True,
|
||||
show_api=True,
|
||||
purpose="logging",
|
||||
)
|
||||
return show_logs(config, args, devices)
|
||||
return show_logs(config, args, port)
|
||||
|
||||
|
||||
def command_clean_mqtt(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_clean_mqtt(args, config):
|
||||
return clean_mqtt(config, args)
|
||||
|
||||
|
||||
def command_mqtt_fingerprint(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_mqtt_fingerprint(args, config):
|
||||
from esphome import mqtt
|
||||
|
||||
return mqtt.get_fingerprint(config)
|
||||
|
||||
|
||||
def command_version(args: ArgsProtocol) -> int | None:
|
||||
def command_version(args):
|
||||
safe_print(f"Version: {const.__version__}")
|
||||
return 0
|
||||
|
||||
|
||||
def command_clean(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_clean(args, config):
|
||||
try:
|
||||
writer.clean_build()
|
||||
except OSError as err:
|
||||
@@ -666,13 +589,13 @@ def command_clean(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return 0
|
||||
|
||||
|
||||
def command_dashboard(args: ArgsProtocol) -> int | None:
|
||||
def command_dashboard(args):
|
||||
from esphome.dashboard import dashboard
|
||||
|
||||
return dashboard.start_dashboard(args)
|
||||
|
||||
|
||||
def command_update_all(args: ArgsProtocol) -> int | None:
|
||||
def command_update_all(args):
|
||||
import click
|
||||
|
||||
success = {}
|
||||
@@ -719,7 +642,7 @@ def command_update_all(args: ArgsProtocol) -> int | None:
|
||||
return failed
|
||||
|
||||
|
||||
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
def command_idedata(args, config):
|
||||
import json
|
||||
|
||||
from esphome import platformio_api
|
||||
@@ -735,7 +658,7 @@ def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def command_rename(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
def command_rename(args, config):
|
||||
for c in args.name:
|
||||
if c not in ALLOWED_NAME_CHARS:
|
||||
print(
|
||||
@@ -852,12 +775,6 @@ POST_CONFIG_ACTIONS = {
|
||||
"discover": command_discover,
|
||||
}
|
||||
|
||||
SIMPLE_CONFIG_ACTIONS = [
|
||||
"clean",
|
||||
"clean-mqtt",
|
||||
"config",
|
||||
]
|
||||
|
||||
|
||||
def parse_args(argv):
|
||||
options_parser = argparse.ArgumentParser(add_help=False)
|
||||
@@ -934,6 +851,17 @@ def parse_args(argv):
|
||||
help="Only generate source code, do not compile.",
|
||||
action="store_true",
|
||||
)
|
||||
parser_compile.add_argument(
|
||||
"--analyze-memory",
|
||||
help="Analyze and display memory usage by component after compilation.",
|
||||
action="store_true",
|
||||
)
|
||||
parser_compile.add_argument(
|
||||
"--memory-report",
|
||||
help="Save memory analysis report to a file (supports .json or .txt).",
|
||||
type=str,
|
||||
metavar="FILE",
|
||||
)
|
||||
|
||||
parser_upload = subparsers.add_parser(
|
||||
"upload",
|
||||
@@ -945,8 +873,7 @@ def parse_args(argv):
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--device",
|
||||
action="append",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--upload_speed",
|
||||
@@ -968,8 +895,7 @@ def parse_args(argv):
|
||||
)
|
||||
parser_logs.add_argument(
|
||||
"--device",
|
||||
action="append",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_logs.add_argument(
|
||||
"--reset",
|
||||
@@ -998,8 +924,7 @@ def parse_args(argv):
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--device",
|
||||
action="append",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--upload_speed",
|
||||
@@ -1126,13 +1051,6 @@ def parse_args(argv):
|
||||
arguments = argv[1:]
|
||||
|
||||
argcomplete.autocomplete(parser)
|
||||
|
||||
if len(arguments) > 0 and arguments[0] in SIMPLE_CONFIG_ACTIONS:
|
||||
args, unknown_args = parser.parse_known_args(arguments)
|
||||
if unknown_args:
|
||||
_LOGGER.warning("Ignored unrecognized arguments: %s", unknown_args)
|
||||
return args
|
||||
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
|
||||
|
1620
esphome/analyze_memory.py
Normal file
1620
esphome/analyze_memory.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -391,7 +391,8 @@ async def build_action(full_config, template_arg, args):
|
||||
)
|
||||
action_id = full_config[CONF_TYPE_ID]
|
||||
builder = registry_entry.coroutine_fun
|
||||
return await builder(config, action_id, template_arg, args)
|
||||
ret = await builder(config, action_id, template_arg, args)
|
||||
return ret
|
||||
|
||||
|
||||
async def build_action_list(config, templ, arg_type):
|
||||
@@ -408,7 +409,8 @@ async def build_condition(full_config, template_arg, args):
|
||||
)
|
||||
action_id = full_config[CONF_TYPE_ID]
|
||||
builder = registry_entry.coroutine_fun
|
||||
return await builder(config, action_id, template_arg, args)
|
||||
ret = await builder(config, action_id, template_arg, args)
|
||||
return ret
|
||||
|
||||
|
||||
async def build_condition_list(config, templ, args):
|
||||
|
@@ -7,6 +7,7 @@ namespace a4988 {
|
||||
static const char *const TAG = "a4988.stepper";
|
||||
|
||||
void A4988::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
if (this->sleep_pin_ != nullptr) {
|
||||
this->sleep_pin_->setup();
|
||||
this->sleep_pin_->digital_write(false);
|
||||
|
@@ -7,6 +7,8 @@ namespace absolute_humidity {
|
||||
static const char *const TAG = "absolute_humidity.sensor";
|
||||
|
||||
void AbsoluteHumidityComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
||||
|
||||
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
|
||||
this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
|
||||
if (this->temperature_sensor_->has_state()) {
|
||||
|
@@ -5,7 +5,7 @@ from esphome.const import (
|
||||
CONF_EQUATION,
|
||||
CONF_HUMIDITY,
|
||||
CONF_TEMPERATURE,
|
||||
DEVICE_CLASS_ABSOLUTE_HUMIDITY,
|
||||
ICON_WATER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_GRAMS_PER_CUBIC_METER,
|
||||
)
|
||||
@@ -27,8 +27,8 @@ EQUATION = {
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_GRAMS_PER_CUBIC_METER,
|
||||
icon=ICON_WATER,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_ABSOLUTE_HUMIDITY,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(
|
||||
|
@@ -1,6 +1,6 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.esp32 import VARIANT_ESP32P4, get_esp32_variant
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
from esphome.components.esp32.const import (
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32C2,
|
||||
@@ -140,16 +140,6 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||
9: adc_channel_t.ADC_CHANNEL_8,
|
||||
10: adc_channel_t.ADC_CHANNEL_9,
|
||||
},
|
||||
VARIANT_ESP32P4: {
|
||||
16: adc_channel_t.ADC_CHANNEL_0,
|
||||
17: adc_channel_t.ADC_CHANNEL_1,
|
||||
18: adc_channel_t.ADC_CHANNEL_2,
|
||||
19: adc_channel_t.ADC_CHANNEL_3,
|
||||
20: adc_channel_t.ADC_CHANNEL_4,
|
||||
21: adc_channel_t.ADC_CHANNEL_5,
|
||||
22: adc_channel_t.ADC_CHANNEL_6,
|
||||
23: adc_channel_t.ADC_CHANNEL_7,
|
||||
},
|
||||
}
|
||||
|
||||
# pin to adc2 channel mapping
|
||||
@@ -208,14 +198,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
||||
19: adc_channel_t.ADC_CHANNEL_8,
|
||||
20: adc_channel_t.ADC_CHANNEL_9,
|
||||
},
|
||||
VARIANT_ESP32P4: {
|
||||
49: adc_channel_t.ADC_CHANNEL_0,
|
||||
50: adc_channel_t.ADC_CHANNEL_1,
|
||||
51: adc_channel_t.ADC_CHANNEL_2,
|
||||
52: adc_channel_t.ADC_CHANNEL_3,
|
||||
53: adc_channel_t.ADC_CHANNEL_4,
|
||||
54: adc_channel_t.ADC_CHANNEL_5,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -267,11 +249,6 @@ def validate_adc_pin(value):
|
||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||
)(value)
|
||||
|
||||
if CORE.is_nrf52:
|
||||
return pins.gpio_pin_schema(
|
||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||
)(value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -288,6 +265,5 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
PlatformFramework.RTL87XX_ARDUINO,
|
||||
PlatformFramework.LN882X_ARDUINO,
|
||||
},
|
||||
"adc_sensor_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
|
||||
}
|
||||
)
|
||||
|
@@ -13,10 +13,6 @@
|
||||
#include "hal/adc_types.h" // This defines ADC_CHANNEL_MAX
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
@@ -42,15 +38,15 @@ enum class SamplingMode : uint8_t {
|
||||
|
||||
const LogString *sampling_mode_to_str(SamplingMode mode);
|
||||
|
||||
template<typename T> class Aggregator {
|
||||
class Aggregator {
|
||||
public:
|
||||
Aggregator(SamplingMode mode);
|
||||
void add_sample(T value);
|
||||
T aggregate();
|
||||
void add_sample(uint32_t value);
|
||||
uint32_t aggregate();
|
||||
|
||||
protected:
|
||||
T aggr_{0};
|
||||
uint8_t samples_{0};
|
||||
uint32_t aggr_{0};
|
||||
uint32_t samples_{0};
|
||||
SamplingMode mode_{SamplingMode::AVG};
|
||||
};
|
||||
|
||||
@@ -73,11 +69,6 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
/// @return A float representing the setup priority.
|
||||
float get_setup_priority() const override;
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
/// Set the ADC channel to be used by the ADC sensor.
|
||||
/// @param channel Pointer to an adc_dt_spec structure representing the ADC channel.
|
||||
void set_adc_channel(const adc_dt_spec *channel) { this->channel_ = channel; }
|
||||
#endif
|
||||
/// Set the GPIO pin to be used by the ADC sensor.
|
||||
/// @param pin Pointer to an InternalGPIOPin representing the ADC input pin.
|
||||
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
|
||||
@@ -145,8 +136,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
adc_oneshot_unit_handle_t adc_handle_{nullptr};
|
||||
adc_cali_handle_t calibration_handle_{nullptr};
|
||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||
adc_channel_t channel_{};
|
||||
adc_unit_t adc_unit_{};
|
||||
adc_channel_t channel_;
|
||||
adc_unit_t adc_unit_;
|
||||
struct SetupFlags {
|
||||
uint8_t init_complete : 1;
|
||||
uint8_t config_complete : 1;
|
||||
@@ -160,10 +151,6 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
#ifdef USE_RP2040
|
||||
bool is_temperature_{false};
|
||||
#endif // USE_RP2040
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
const struct adc_dt_spec *channel_ = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
|
@@ -18,15 +18,15 @@ const LogString *sampling_mode_to_str(SamplingMode mode) {
|
||||
return LOG_STR("unknown");
|
||||
}
|
||||
|
||||
template<typename T> Aggregator<T>::Aggregator(SamplingMode mode) {
|
||||
Aggregator::Aggregator(SamplingMode mode) {
|
||||
this->mode_ = mode;
|
||||
// set to max uint if mode is "min"
|
||||
if (mode == SamplingMode::MIN) {
|
||||
this->aggr_ = std::numeric_limits<T>::max();
|
||||
this->aggr_ = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Aggregator<T>::add_sample(T value) {
|
||||
void Aggregator::add_sample(uint32_t value) {
|
||||
this->samples_ += 1;
|
||||
|
||||
switch (this->mode_) {
|
||||
@@ -47,7 +47,7 @@ template<typename T> void Aggregator<T>::add_sample(T value) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> T Aggregator<T>::aggregate() {
|
||||
uint32_t Aggregator::aggregate() {
|
||||
if (this->mode_ == SamplingMode::AVG) {
|
||||
if (this->samples_ == 0) {
|
||||
return this->aggr_;
|
||||
@@ -59,12 +59,6 @@ template<typename T> T Aggregator<T>::aggregate() {
|
||||
return this->aggr_;
|
||||
}
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
template class Aggregator<int32_t>;
|
||||
#else
|
||||
template class Aggregator<uint32_t>;
|
||||
#endif
|
||||
|
||||
void ADCSensor::update() {
|
||||
float value_v = this->sample();
|
||||
ESP_LOGV(TAG, "'%s': Voltage=%.4fV", this->get_name().c_str(), value_v);
|
||||
|
@@ -37,6 +37,7 @@ const LogString *adc_unit_to_str(adc_unit_t unit) {
|
||||
}
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
||||
// Check if another sensor already initialized this ADC unit
|
||||
if (ADCSensor::shared_adc_handles[this->adc_unit_] == nullptr) {
|
||||
adc_oneshot_unit_init_cfg_t init_config = {}; // Zero initialize
|
||||
@@ -72,9 +73,10 @@ void ADCSensor::setup() {
|
||||
// Initialize ADC calibration
|
||||
if (this->calibration_handle_ == nullptr) {
|
||||
adc_cali_handle_t handle = nullptr;
|
||||
esp_err_t err;
|
||||
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
// RISC-V variants and S3 use curve fitting calibration
|
||||
adc_cali_curve_fitting_config_t cali_config = {}; // Zero initialize first
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
@@ -152,7 +154,7 @@ float ADCSensor::sample() {
|
||||
}
|
||||
|
||||
float ADCSensor::sample_fixed_attenuation_() {
|
||||
auto aggr = Aggregator<uint32_t>(this->sampling_mode_);
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
int raw;
|
||||
@@ -186,7 +188,7 @@ float ADCSensor::sample_fixed_attenuation_() {
|
||||
ESP_LOGW(TAG, "ADC calibration conversion failed with error %d, disabling calibration", err);
|
||||
if (this->calibration_handle_ != nullptr) {
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
|
||||
#else // Other ESP32 variants use line fitting calibration
|
||||
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
|
||||
@@ -219,7 +221,7 @@ float ADCSensor::sample_autorange_() {
|
||||
if (this->calibration_handle_ != nullptr) {
|
||||
// Delete old calibration handle
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
|
||||
@@ -231,7 +233,7 @@ float ADCSensor::sample_autorange_() {
|
||||
adc_cali_handle_t handle = nullptr;
|
||||
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
adc_cali_curve_fitting_config_t cali_config = {};
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
cali_config.chan = this->channel_;
|
||||
@@ -260,7 +262,7 @@ float ADCSensor::sample_autorange_() {
|
||||
ESP_LOGW(TAG, "ADC read failed in autorange with error %d", err);
|
||||
if (handle != nullptr) {
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
adc_cali_delete_scheme_curve_fitting(handle);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(handle);
|
||||
@@ -280,7 +282,7 @@ float ADCSensor::sample_autorange_() {
|
||||
}
|
||||
// Clean up calibration handle
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2
|
||||
adc_cali_delete_scheme_curve_fitting(handle);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(handle);
|
||||
|
@@ -17,6 +17,7 @@ namespace adc {
|
||||
static const char *const TAG = "adc.esp8266";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
||||
#ifndef USE_ADC_SENSOR_VCC
|
||||
this->pin_->setup();
|
||||
#endif
|
||||
@@ -37,7 +38,7 @@ void ADCSensor::dump_config() {
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
auto aggr = Aggregator<uint32_t>(this->sampling_mode_);
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
uint32_t raw = 0;
|
||||
|
@@ -9,6 +9,7 @@ namespace adc {
|
||||
static const char *const TAG = "adc.libretiny";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
||||
#ifndef USE_ADC_SENSOR_VCC
|
||||
this->pin_->setup();
|
||||
#endif // !USE_ADC_SENSOR_VCC
|
||||
@@ -30,7 +31,7 @@ void ADCSensor::dump_config() {
|
||||
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
auto aggr = Aggregator<uint32_t>(this->sampling_mode_);
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
if (this->output_raw_) {
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
|
@@ -14,6 +14,7 @@ namespace adc {
|
||||
static const char *const TAG = "adc.rp2040";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
adc_init();
|
||||
@@ -41,7 +42,7 @@ void ADCSensor::dump_config() {
|
||||
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
auto aggr = Aggregator<uint32_t>(this->sampling_mode_);
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
if (this->is_temperature_) {
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
|
@@ -1,207 +0,0 @@
|
||||
|
||||
#include "adc_sensor.h"
|
||||
#ifdef USE_ZEPHYR
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include "hal/nrf_saadc.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.zephyr";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
if (!adc_is_ready_dt(this->channel_)) {
|
||||
ESP_LOGE(TAG, "ADC controller device %s not ready", this->channel_->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
auto err = adc_channel_setup_dt(this->channel_);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Could not setup channel %s (%d)", this->channel_->dev->name, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
static const LogString *gain_to_str(enum adc_gain gain) {
|
||||
switch (gain) {
|
||||
case ADC_GAIN_1_6:
|
||||
return LOG_STR("1/6");
|
||||
case ADC_GAIN_1_5:
|
||||
return LOG_STR("1/5");
|
||||
case ADC_GAIN_1_4:
|
||||
return LOG_STR("1/4");
|
||||
case ADC_GAIN_1_3:
|
||||
return LOG_STR("1/3");
|
||||
case ADC_GAIN_2_5:
|
||||
return LOG_STR("2/5");
|
||||
case ADC_GAIN_1_2:
|
||||
return LOG_STR("1/2");
|
||||
case ADC_GAIN_2_3:
|
||||
return LOG_STR("2/3");
|
||||
case ADC_GAIN_4_5:
|
||||
return LOG_STR("4/5");
|
||||
case ADC_GAIN_1:
|
||||
return LOG_STR("1");
|
||||
case ADC_GAIN_2:
|
||||
return LOG_STR("2");
|
||||
case ADC_GAIN_3:
|
||||
return LOG_STR("3");
|
||||
case ADC_GAIN_4:
|
||||
return LOG_STR("4");
|
||||
case ADC_GAIN_6:
|
||||
return LOG_STR("6");
|
||||
case ADC_GAIN_8:
|
||||
return LOG_STR("8");
|
||||
case ADC_GAIN_12:
|
||||
return LOG_STR("12");
|
||||
case ADC_GAIN_16:
|
||||
return LOG_STR("16");
|
||||
case ADC_GAIN_24:
|
||||
return LOG_STR("24");
|
||||
case ADC_GAIN_32:
|
||||
return LOG_STR("32");
|
||||
case ADC_GAIN_64:
|
||||
return LOG_STR("64");
|
||||
case ADC_GAIN_128:
|
||||
return LOG_STR("128");
|
||||
}
|
||||
return LOG_STR("undefined gain");
|
||||
}
|
||||
|
||||
static const LogString *reference_to_str(enum adc_reference reference) {
|
||||
switch (reference) {
|
||||
case ADC_REF_VDD_1:
|
||||
return LOG_STR("VDD");
|
||||
case ADC_REF_VDD_1_2:
|
||||
return LOG_STR("VDD/2");
|
||||
case ADC_REF_VDD_1_3:
|
||||
return LOG_STR("VDD/3");
|
||||
case ADC_REF_VDD_1_4:
|
||||
return LOG_STR("VDD/4");
|
||||
case ADC_REF_INTERNAL:
|
||||
return LOG_STR("INTERNAL");
|
||||
case ADC_REF_EXTERNAL0:
|
||||
return LOG_STR("External, input 0");
|
||||
case ADC_REF_EXTERNAL1:
|
||||
return LOG_STR("External, input 1");
|
||||
}
|
||||
return LOG_STR("undefined reference");
|
||||
}
|
||||
|
||||
static const LogString *input_to_str(uint8_t input) {
|
||||
switch (input) {
|
||||
case NRF_SAADC_INPUT_AIN0:
|
||||
return LOG_STR("AIN0");
|
||||
case NRF_SAADC_INPUT_AIN1:
|
||||
return LOG_STR("AIN1");
|
||||
case NRF_SAADC_INPUT_AIN2:
|
||||
return LOG_STR("AIN2");
|
||||
case NRF_SAADC_INPUT_AIN3:
|
||||
return LOG_STR("AIN3");
|
||||
case NRF_SAADC_INPUT_AIN4:
|
||||
return LOG_STR("AIN4");
|
||||
case NRF_SAADC_INPUT_AIN5:
|
||||
return LOG_STR("AIN5");
|
||||
case NRF_SAADC_INPUT_AIN6:
|
||||
return LOG_STR("AIN6");
|
||||
case NRF_SAADC_INPUT_AIN7:
|
||||
return LOG_STR("AIN7");
|
||||
case NRF_SAADC_INPUT_VDD:
|
||||
return LOG_STR("VDD");
|
||||
case NRF_SAADC_INPUT_VDDHDIV5:
|
||||
return LOG_STR("VDDHDIV5");
|
||||
}
|
||||
return LOG_STR("undefined input");
|
||||
}
|
||||
#endif // ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
ESP_LOGV(TAG,
|
||||
" Name: %s\n"
|
||||
" Channel: %d\n"
|
||||
" vref_mv: %d\n"
|
||||
" Resolution %d\n"
|
||||
" Oversampling %d",
|
||||
this->channel_->dev->name, this->channel_->channel_id, this->channel_->vref_mv, this->channel_->resolution,
|
||||
this->channel_->oversampling);
|
||||
|
||||
ESP_LOGV(TAG,
|
||||
" Gain: %s\n"
|
||||
" reference: %s\n"
|
||||
" acquisition_time: %d\n"
|
||||
" differential %s",
|
||||
LOG_STR_ARG(gain_to_str(this->channel_->channel_cfg.gain)),
|
||||
LOG_STR_ARG(reference_to_str(this->channel_->channel_cfg.reference)),
|
||||
this->channel_->channel_cfg.acquisition_time, YESNO(this->channel_->channel_cfg.differential));
|
||||
if (this->channel_->channel_cfg.differential) {
|
||||
ESP_LOGV(TAG,
|
||||
" Positive: %s\n"
|
||||
" Negative: %s",
|
||||
LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_positive)),
|
||||
LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_negative)));
|
||||
} else {
|
||||
ESP_LOGV(TAG, " Positive: %s", LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_positive)));
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
auto aggr = Aggregator<int32_t>(this->sampling_mode_);
|
||||
int err;
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
int16_t buf = 0;
|
||||
struct adc_sequence sequence = {
|
||||
.buffer = &buf,
|
||||
/* buffer size in bytes, not number of samples */
|
||||
.buffer_size = sizeof(buf),
|
||||
};
|
||||
int32_t val_raw;
|
||||
|
||||
err = adc_sequence_init_dt(this->channel_, &sequence);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Could sequence init %s (%d)", this->channel_->dev->name, err);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
err = adc_read(this->channel_->dev, &sequence);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Could not read %s (%d)", this->channel_->dev->name, err);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
val_raw = (int32_t) buf;
|
||||
if (!this->channel_->channel_cfg.differential) {
|
||||
// https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/0ed4d9ffc674ae407be7cacf5696a02f5e789861/cores/nRF5/wiring_analog_nRF52.c#L222
|
||||
if (val_raw < 0) {
|
||||
val_raw = 0;
|
||||
}
|
||||
}
|
||||
aggr.add_sample(val_raw);
|
||||
}
|
||||
|
||||
int32_t val_mv = aggr.aggregate();
|
||||
|
||||
if (this->output_raw_) {
|
||||
return val_mv;
|
||||
}
|
||||
|
||||
err = adc_raw_to_millivolts_dt(this->channel_, &val_mv);
|
||||
/* conversion to mV may not be supported, skip if not */
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Value in mV not available %s (%d)", this->channel_->dev->name, err);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return val_mv / 1000.0f;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
#endif
|
@@ -3,12 +3,6 @@ import logging
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
from esphome.components.nrf52.const import AIN_TO_GPIO, EXTRA_ADC
|
||||
from esphome.components.zephyr import (
|
||||
zephyr_add_overlay,
|
||||
zephyr_add_prj_conf,
|
||||
zephyr_add_user,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ATTENUATION,
|
||||
@@ -17,7 +11,6 @@ from esphome.const import (
|
||||
CONF_PIN,
|
||||
CONF_RAW,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
PLATFORM_NRF52,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
)
|
||||
@@ -67,10 +60,6 @@ ADCSensor = adc_ns.class_(
|
||||
"ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
|
||||
)
|
||||
|
||||
CONF_NRF_SAADC = "nrf_saadc"
|
||||
|
||||
adc_dt_spec = cg.global_ns.class_("adc_dt_spec")
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(
|
||||
ADCSensor,
|
||||
@@ -86,7 +75,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
|
||||
cv.only_on_esp32, _attenuation
|
||||
),
|
||||
cv.OnlyWith(CONF_NRF_SAADC, PLATFORM_NRF52): cv.declare_id(adc_dt_spec),
|
||||
cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
|
||||
cv.Optional(CONF_SAMPLING_MODE, default="avg"): _sampling_mode,
|
||||
}
|
||||
@@ -95,8 +83,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
validate_config,
|
||||
)
|
||||
|
||||
CONF_ADC_CHANNEL_ID = "adc_channel_id"
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
@@ -107,7 +93,7 @@ async def to_code(config):
|
||||
cg.add_define("USE_ADC_SENSOR_VCC")
|
||||
elif config[CONF_PIN] == "TEMPERATURE":
|
||||
cg.add(var.set_is_temperature())
|
||||
elif not CORE.is_nrf52 or config[CONF_PIN][CONF_NUMBER] not in EXTRA_ADC:
|
||||
else:
|
||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||
cg.add(var.set_pin(pin))
|
||||
|
||||
@@ -136,41 +122,3 @@ async def to_code(config):
|
||||
):
|
||||
chan = ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant][pin_num]
|
||||
cg.add(var.set_channel(adc_unit_t.ADC_UNIT_2, chan))
|
||||
|
||||
elif CORE.is_nrf52:
|
||||
CORE.data.setdefault(CONF_ADC_CHANNEL_ID, 0)
|
||||
channel_id = CORE.data[CONF_ADC_CHANNEL_ID]
|
||||
CORE.data[CONF_ADC_CHANNEL_ID] = channel_id + 1
|
||||
zephyr_add_prj_conf("ADC", True)
|
||||
nrf_saadc = config[CONF_NRF_SAADC]
|
||||
rhs = cg.RawExpression(
|
||||
f"ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), {channel_id})"
|
||||
)
|
||||
adc = cg.new_Pvariable(nrf_saadc, rhs)
|
||||
cg.add(var.set_adc_channel(adc))
|
||||
gain = "ADC_GAIN_1_6"
|
||||
pin_number = config[CONF_PIN][CONF_NUMBER]
|
||||
if pin_number == "VDDHDIV5":
|
||||
gain = "ADC_GAIN_1_2"
|
||||
if isinstance(pin_number, int):
|
||||
GPIO_TO_AIN = {v: k for k, v in AIN_TO_GPIO.items()}
|
||||
pin_number = GPIO_TO_AIN[pin_number]
|
||||
zephyr_add_user("io-channels", f"<&adc {channel_id}>")
|
||||
zephyr_add_overlay(
|
||||
f"""
|
||||
&adc {{
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@{channel_id} {{
|
||||
reg = <{channel_id}>;
|
||||
zephyr,gain = "{gain}";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,input-positive = <NRF_SAADC_{pin_number}>;
|
||||
zephyr,resolution = <14>;
|
||||
zephyr,oversampling = <8>;
|
||||
}};
|
||||
}};
|
||||
"""
|
||||
)
|
||||
|
@@ -8,7 +8,10 @@ static const char *const TAG = "adc128s102";
|
||||
|
||||
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
void ADC128S102::setup() { this->spi_setup(); }
|
||||
void ADC128S102::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->spi_setup();
|
||||
}
|
||||
|
||||
void ADC128S102::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADC128S102:");
|
||||
|
@@ -10,6 +10,7 @@ static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
||||
|
||||
void ADS1115Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint16_t value;
|
||||
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
|
||||
this->mark_failed();
|
||||
|
@@ -9,6 +9,7 @@ static const char *const TAG = "ads1118";
|
||||
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
|
||||
|
||||
void ADS1118::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->spi_setup();
|
||||
|
||||
this->config_ = 0;
|
||||
|
@@ -24,6 +24,8 @@ static const uint16_t ZP_CURRENT = 0x0000;
|
||||
static const uint16_t ZP_DEFAULT = 0xFFFF;
|
||||
|
||||
void AGS10Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
auto version = this->read_version_();
|
||||
if (version) {
|
||||
ESP_LOGD(TAG, "AGS10 Sensor Version: 0x%02X", *version);
|
||||
@@ -43,6 +45,8 @@ void AGS10Component::setup() {
|
||||
} else {
|
||||
ESP_LOGE(TAG, "AGS10 Sensor Resistance: unknown");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Sensor initialized");
|
||||
}
|
||||
|
||||
void AGS10Component::update() {
|
||||
|
@@ -38,6 +38,8 @@ static const uint8_t AHT10_STATUS_BUSY = 0x80;
|
||||
static const float AHT10_DIVISOR = 1048576.0f; // 2^20, used for temperature and humidity calculations
|
||||
|
||||
void AHT10Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Reset failed");
|
||||
}
|
||||
@@ -78,6 +80,8 @@ void AHT10Component::setup() {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Initialization complete");
|
||||
}
|
||||
|
||||
void AHT10Component::restart_read_() {
|
||||
|
@@ -17,6 +17,8 @@ static const char *const TAG = "aic3204";
|
||||
}
|
||||
|
||||
void AIC3204::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
// Set register page to 0
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
|
||||
// Initiate SW reset (PLL is powered off as part of reset)
|
||||
|
@@ -301,7 +301,8 @@ async def alarm_action_disarm_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def alarm_action_pending_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -309,7 +310,8 @@ async def alarm_action_pending_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def alarm_action_trigger_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -317,7 +319,8 @@ async def alarm_action_trigger_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def alarm_action_chime_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -330,7 +333,8 @@ async def alarm_action_chime_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def alarm_action_ready_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_condition(
|
||||
@@ -348,3 +352,4 @@ async def alarm_control_panel_is_armed_to_code(
|
||||
@coroutine_with_priority(100.0)
|
||||
async def to_code(config):
|
||||
cg.add_global(alarm_control_panel_ns.using)
|
||||
cg.add_define("USE_ALARM_CONTROL_PANEL")
|
||||
|
@@ -90,6 +90,8 @@ bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
|
||||
}
|
||||
|
||||
void AM2315C::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
// get status
|
||||
uint8_t status = 0;
|
||||
if (this->read(&status, 1) != i2c::ERROR_OK) {
|
||||
|
@@ -34,6 +34,7 @@ void AM2320Component::update() {
|
||||
this->status_clear_warning();
|
||||
}
|
||||
void AM2320Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t data[8];
|
||||
data[0] = 0;
|
||||
data[1] = 4;
|
||||
|
@@ -34,20 +34,17 @@ SetFrameAction = animation_ns.class_(
|
||||
"AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
espImage.IMAGE_SCHEMA.extend(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(Animation_),
|
||||
cv.Optional(CONF_LOOP): cv.All(
|
||||
{
|
||||
cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_END_FRAME): cv.positive_int,
|
||||
cv.Optional(CONF_REPEAT): cv.positive_int,
|
||||
}
|
||||
),
|
||||
},
|
||||
),
|
||||
espImage.validate_settings,
|
||||
CONFIG_SCHEMA = espImage.IMAGE_SCHEMA.extend(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(Animation_),
|
||||
cv.Optional(CONF_LOOP): cv.All(
|
||||
{
|
||||
cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_END_FRAME): cv.positive_int,
|
||||
cv.Optional(CONF_REPEAT): cv.positive_int,
|
||||
}
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
|
@@ -54,6 +54,8 @@ enum { // APDS9306 registers
|
||||
}
|
||||
|
||||
void APDS9306::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
uint8_t id;
|
||||
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
@@ -84,6 +86,8 @@ void APDS9306::setup() {
|
||||
|
||||
// Set to active mode
|
||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
|
||||
|
||||
ESP_LOGCONFIG(TAG, "APDS9306 setup complete");
|
||||
}
|
||||
|
||||
void APDS9306::dump_config() {
|
||||
|
@@ -15,6 +15,7 @@ static const char *const TAG = "apds9960";
|
||||
#define APDS9960_WRITE_BYTE(reg, value) APDS9960_ERROR_CHECK(this->write_byte(reg, value));
|
||||
|
||||
void APDS9960::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t id;
|
||||
if (!this->read_byte(0x92, &id)) { // ID register
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
|
@@ -29,7 +29,7 @@ from esphome.core import CORE, coroutine_with_priority
|
||||
DOMAIN = "api"
|
||||
DEPENDENCIES = ["network"]
|
||||
AUTO_LOAD = ["socket"]
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
CODEOWNERS = ["@OttoWinter"]
|
||||
|
||||
api_ns = cg.esphome_ns.namespace("api")
|
||||
APIServer = api_ns.class_("APIServer", cg.Component, cg.Controller)
|
||||
@@ -53,8 +53,6 @@ SERVICE_ARG_NATIVE_TYPES = {
|
||||
CONF_ENCRYPTION = "encryption"
|
||||
CONF_BATCH_DELAY = "batch_delay"
|
||||
CONF_CUSTOM_SERVICES = "custom_services"
|
||||
CONF_HOMEASSISTANT_SERVICES = "homeassistant_services"
|
||||
CONF_HOMEASSISTANT_STATES = "homeassistant_states"
|
||||
|
||||
|
||||
def validate_encryption_key(value):
|
||||
@@ -120,8 +118,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Range(max=cv.TimePeriod(milliseconds=65535)),
|
||||
),
|
||||
cv.Optional(CONF_CUSTOM_SERVICES, default=False): cv.boolean,
|
||||
cv.Optional(CONF_HOMEASSISTANT_SERVICES, default=False): cv.boolean,
|
||||
cv.Optional(CONF_HOMEASSISTANT_STATES, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
@@ -150,12 +146,6 @@ async def to_code(config):
|
||||
if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]:
|
||||
cg.add_define("USE_API_SERVICES")
|
||||
|
||||
if config[CONF_HOMEASSISTANT_SERVICES]:
|
||||
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
||||
|
||||
if config[CONF_HOMEASSISTANT_STATES]:
|
||||
cg.add_define("USE_API_HOMEASSISTANT_STATES")
|
||||
|
||||
if actions := config.get(CONF_ACTIONS, []):
|
||||
for conf in actions:
|
||||
template_args = []
|
||||
@@ -245,7 +235,6 @@ HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
||||
)
|
||||
async def homeassistant_service_to_code(config, action_id, template_arg, args):
|
||||
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, False)
|
||||
templ = await cg.templatable(config[CONF_ACTION], args, None)
|
||||
@@ -289,7 +278,6 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema(
|
||||
HOMEASSISTANT_EVENT_ACTION_SCHEMA,
|
||||
)
|
||||
async def homeassistant_event_to_code(config, action_id, template_arg, args):
|
||||
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, True)
|
||||
templ = await cg.templatable(config[CONF_EVENT], args, None)
|
||||
|
@@ -250,8 +250,8 @@ message DeviceInfoResponse {
|
||||
// Supports receiving and saving api encryption key
|
||||
bool api_encryption_supported = 19 [(field_ifdef) = "USE_API_NOISE"];
|
||||
|
||||
repeated DeviceInfo devices = 20 [(field_ifdef) = "USE_DEVICES", (fixed_array_size_define) = "ESPHOME_DEVICE_COUNT"];
|
||||
repeated AreaInfo areas = 21 [(field_ifdef) = "USE_AREAS", (fixed_array_size_define) = "ESPHOME_AREA_COUNT"];
|
||||
repeated DeviceInfo devices = 20 [(field_ifdef) = "USE_DEVICES"];
|
||||
repeated AreaInfo areas = 21 [(field_ifdef) = "USE_AREAS"];
|
||||
|
||||
// Top-level area info to phase out suggested_area
|
||||
AreaInfo area = 22 [(field_ifdef) = "USE_AREAS"];
|
||||
@@ -419,7 +419,7 @@ message ListEntitiesFanResponse {
|
||||
bool disabled_by_default = 9;
|
||||
string icon = 10 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
EntityCategory entity_category = 11;
|
||||
repeated string supported_preset_modes = 12 [(container_pointer) = "std::set"];
|
||||
repeated string supported_preset_modes = 12;
|
||||
uint32 device_id = 13 [(field_ifdef) = "USE_DEVICES"];
|
||||
}
|
||||
// Deprecated in API version 1.6 - only used in deprecated fields
|
||||
@@ -500,7 +500,7 @@ message ListEntitiesLightResponse {
|
||||
string name = 3;
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
repeated ColorMode supported_color_modes = 12 [(container_pointer) = "std::set<light::ColorMode>"];
|
||||
repeated ColorMode supported_color_modes = 12;
|
||||
// next four supports_* are for legacy clients, newer clients should use color modes
|
||||
// Deprecated in API version 1.6
|
||||
bool legacy_supports_brightness = 5 [deprecated=true];
|
||||
@@ -755,19 +755,17 @@ message NoiseEncryptionSetKeyResponse {
|
||||
message SubscribeHomeassistantServicesRequest {
|
||||
option (id) = 34;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_API_HOMEASSISTANT_SERVICES";
|
||||
}
|
||||
|
||||
message HomeassistantServiceMap {
|
||||
string key = 1;
|
||||
string value = 2 [(no_zero_copy) = true];
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message HomeassistantServiceResponse {
|
||||
option (id) = 35;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (no_delay) = true;
|
||||
option (ifdef) = "USE_API_HOMEASSISTANT_SERVICES";
|
||||
|
||||
string service = 1;
|
||||
repeated HomeassistantServiceMap data = 2;
|
||||
@@ -783,13 +781,11 @@ message HomeassistantServiceResponse {
|
||||
message SubscribeHomeAssistantStatesRequest {
|
||||
option (id) = 38;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_API_HOMEASSISTANT_STATES";
|
||||
}
|
||||
|
||||
message SubscribeHomeAssistantStateResponse {
|
||||
option (id) = 39;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_API_HOMEASSISTANT_STATES";
|
||||
string entity_id = 1;
|
||||
string attribute = 2;
|
||||
bool once = 3;
|
||||
@@ -799,7 +795,6 @@ message HomeAssistantStateResponse {
|
||||
option (id) = 40;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (no_delay) = true;
|
||||
option (ifdef) = "USE_API_HOMEASSISTANT_STATES";
|
||||
|
||||
string entity_id = 1;
|
||||
string state = 2;
|
||||
@@ -966,7 +961,7 @@ message ListEntitiesClimateResponse {
|
||||
|
||||
bool supports_current_temperature = 5;
|
||||
bool supports_two_point_target_temperature = 6;
|
||||
repeated ClimateMode supported_modes = 7 [(container_pointer) = "std::set<climate::ClimateMode>"];
|
||||
repeated ClimateMode supported_modes = 7;
|
||||
float visual_min_temperature = 8;
|
||||
float visual_max_temperature = 9;
|
||||
float visual_target_temperature_step = 10;
|
||||
@@ -975,11 +970,11 @@ message ListEntitiesClimateResponse {
|
||||
// Deprecated in API version 1.5
|
||||
bool legacy_supports_away = 11 [deprecated=true];
|
||||
bool supports_action = 12;
|
||||
repeated ClimateFanMode supported_fan_modes = 13 [(container_pointer) = "std::set<climate::ClimateFanMode>"];
|
||||
repeated ClimateSwingMode supported_swing_modes = 14 [(container_pointer) = "std::set<climate::ClimateSwingMode>"];
|
||||
repeated string supported_custom_fan_modes = 15 [(container_pointer) = "std::set"];
|
||||
repeated ClimatePreset supported_presets = 16 [(container_pointer) = "std::set<climate::ClimatePreset>"];
|
||||
repeated string supported_custom_presets = 17 [(container_pointer) = "std::set"];
|
||||
repeated ClimateFanMode supported_fan_modes = 13;
|
||||
repeated ClimateSwingMode supported_swing_modes = 14;
|
||||
repeated string supported_custom_fan_modes = 15;
|
||||
repeated ClimatePreset supported_presets = 16;
|
||||
repeated string supported_custom_presets = 17;
|
||||
bool disabled_by_default = 18;
|
||||
string icon = 19 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
EntityCategory entity_category = 20;
|
||||
@@ -1119,7 +1114,7 @@ message ListEntitiesSelectResponse {
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||
repeated string options = 6 [(container_pointer) = "std::vector"];
|
||||
repeated string options = 6;
|
||||
bool disabled_by_default = 7;
|
||||
EntityCategory entity_category = 8;
|
||||
uint32 device_id = 9 [(field_ifdef) = "USE_DEVICES"];
|
||||
@@ -1297,9 +1292,6 @@ enum MediaPlayerState {
|
||||
MEDIA_PLAYER_STATE_IDLE = 1;
|
||||
MEDIA_PLAYER_STATE_PLAYING = 2;
|
||||
MEDIA_PLAYER_STATE_PAUSED = 3;
|
||||
MEDIA_PLAYER_STATE_ANNOUNCING = 4;
|
||||
MEDIA_PLAYER_STATE_OFF = 5;
|
||||
MEDIA_PLAYER_STATE_ON = 6;
|
||||
}
|
||||
enum MediaPlayerCommand {
|
||||
MEDIA_PLAYER_COMMAND_PLAY = 0;
|
||||
@@ -1307,15 +1299,6 @@ enum MediaPlayerCommand {
|
||||
MEDIA_PLAYER_COMMAND_STOP = 2;
|
||||
MEDIA_PLAYER_COMMAND_MUTE = 3;
|
||||
MEDIA_PLAYER_COMMAND_UNMUTE = 4;
|
||||
MEDIA_PLAYER_COMMAND_TOGGLE = 5;
|
||||
MEDIA_PLAYER_COMMAND_VOLUME_UP = 6;
|
||||
MEDIA_PLAYER_COMMAND_VOLUME_DOWN = 7;
|
||||
MEDIA_PLAYER_COMMAND_ENQUEUE = 8;
|
||||
MEDIA_PLAYER_COMMAND_REPEAT_ONE = 9;
|
||||
MEDIA_PLAYER_COMMAND_REPEAT_OFF = 10;
|
||||
MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 11;
|
||||
MEDIA_PLAYER_COMMAND_TURN_ON = 12;
|
||||
MEDIA_PLAYER_COMMAND_TURN_OFF = 13;
|
||||
}
|
||||
enum MediaPlayerFormatPurpose {
|
||||
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0;
|
||||
@@ -1350,8 +1333,6 @@ message ListEntitiesMediaPlayerResponse {
|
||||
repeated MediaPlayerSupportedFormat supported_formats = 9;
|
||||
|
||||
uint32 device_id = 10 [(field_ifdef) = "USE_DEVICES"];
|
||||
|
||||
uint32 feature_flags = 11;
|
||||
}
|
||||
message MediaPlayerStateResponse {
|
||||
option (id) = 64;
|
||||
@@ -1442,7 +1423,7 @@ message BluetoothLERawAdvertisementsResponse {
|
||||
}
|
||||
|
||||
enum BluetoothDeviceRequestType {
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0 [deprecated = true]; // V1 removed, use V3 variants
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
|
||||
@@ -1482,39 +1463,21 @@ message BluetoothGATTGetServicesRequest {
|
||||
}
|
||||
|
||||
message BluetoothGATTDescriptor {
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true];
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2];
|
||||
uint32 handle = 2;
|
||||
|
||||
// New field for efficient UUID (v1.12+)
|
||||
// Only one of uuid or short_uuid will be set.
|
||||
// short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients.
|
||||
// 128-bit UUIDs always use the uuid field for backwards compatibility.
|
||||
uint32 short_uuid = 3; // 16-bit or 32-bit UUID
|
||||
}
|
||||
|
||||
message BluetoothGATTCharacteristic {
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true];
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2];
|
||||
uint32 handle = 2;
|
||||
uint32 properties = 3;
|
||||
repeated BluetoothGATTDescriptor descriptors = 4;
|
||||
|
||||
// New field for efficient UUID (v1.12+)
|
||||
// Only one of uuid or short_uuid will be set.
|
||||
// short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients.
|
||||
// 128-bit UUIDs always use the uuid field for backwards compatibility.
|
||||
uint32 short_uuid = 5; // 16-bit or 32-bit UUID
|
||||
}
|
||||
|
||||
message BluetoothGATTService {
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true];
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2];
|
||||
uint32 handle = 2;
|
||||
repeated BluetoothGATTCharacteristic characteristics = 3;
|
||||
|
||||
// New field for efficient UUID (v1.12+)
|
||||
// Only one of uuid or short_uuid will be set.
|
||||
// short_uuid is used for both 16-bit and 32-bit UUIDs with v1.12+ clients.
|
||||
// 128-bit UUIDs always use the uuid field for backwards compatibility.
|
||||
uint32 short_uuid = 4; // 16-bit or 32-bit UUID
|
||||
}
|
||||
|
||||
message BluetoothGATTGetServicesResponse {
|
||||
@@ -1523,7 +1486,7 @@ message BluetoothGATTGetServicesResponse {
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
repeated BluetoothGATTService services = 2;
|
||||
repeated BluetoothGATTService services = 2 [(fixed_array_size) = 1];
|
||||
}
|
||||
|
||||
message BluetoothGATTGetServicesDoneResponse {
|
||||
@@ -1621,10 +1584,7 @@ message BluetoothConnectionsFreeResponse {
|
||||
|
||||
uint32 free = 1;
|
||||
uint32 limit = 2;
|
||||
repeated uint64 allocated = 3 [
|
||||
(fixed_array_size_define) = "BLUETOOTH_PROXY_MAX_CONNECTIONS",
|
||||
(fixed_array_skip_zero) = true
|
||||
];
|
||||
repeated uint64 allocated = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTErrorResponse {
|
||||
@@ -1869,7 +1829,7 @@ message VoiceAssistantConfigurationResponse {
|
||||
option (ifdef) = "USE_VOICE_ASSISTANT";
|
||||
|
||||
repeated VoiceAssistantWakeWord available_wake_words = 1;
|
||||
repeated string active_wake_words = 2 [(container_pointer) = "std::vector"];
|
||||
repeated string active_wake_words = 2;
|
||||
uint32 max_active_wake_words = 3;
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,8 @@
|
||||
#include "esphome/components/voice_assistant/voice_assistant.h"
|
||||
#endif
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Read a maximum of 5 messages per loop iteration to prevent starving other components.
|
||||
// This is a balance between API responsiveness and allowing other components to run.
|
||||
@@ -112,7 +113,8 @@ void APIConnection::start() {
|
||||
APIError err = this->helper_->init();
|
||||
if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
this->log_warning_("Helper init failed", err);
|
||||
ESP_LOGW(TAG, "%s: Helper init failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
||||
errno);
|
||||
return;
|
||||
}
|
||||
this->client_info_.peername = helper_->getpeername();
|
||||
@@ -143,7 +145,8 @@ void APIConnection::loop() {
|
||||
APIError err = this->helper_->loop();
|
||||
if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
this->log_socket_operation_failed_(err);
|
||||
ESP_LOGW(TAG, "%s: Socket operation failed %s errno=%d", this->get_client_combined_info().c_str(),
|
||||
api_error_to_str(err), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,7 +162,8 @@ void APIConnection::loop() {
|
||||
break;
|
||||
} else if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
this->log_warning_("Reading failed", err);
|
||||
ESP_LOGW(TAG, "%s: Reading failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
||||
errno);
|
||||
return;
|
||||
} else {
|
||||
this->last_traffic_ = now;
|
||||
@@ -239,11 +243,23 @@ void APIConnection::loop() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
if (state_subs_at_ >= 0) {
|
||||
this->process_state_subscriptions_();
|
||||
const auto &subs = this->parent_->get_state_subs();
|
||||
if (state_subs_at_ < static_cast<int>(subs.size())) {
|
||||
auto &it = subs[state_subs_at_];
|
||||
SubscribeHomeAssistantStateResponse resp;
|
||||
resp.set_entity_id(StringRef(it.entity_id));
|
||||
// attribute.value() returns temporary - must store it
|
||||
std::string attribute_value = it.attribute.value();
|
||||
resp.set_attribute(StringRef(attribute_value));
|
||||
resp.once = it.once;
|
||||
if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
|
||||
state_subs_at_++;
|
||||
}
|
||||
} else {
|
||||
state_subs_at_ = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
|
||||
@@ -273,9 +289,8 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint8_t mess
|
||||
#endif
|
||||
|
||||
// Calculate size
|
||||
ProtoSize size_calc;
|
||||
msg.calculate_size(size_calc);
|
||||
uint32_t calculated_size = size_calc.get_size();
|
||||
uint32_t calculated_size = 0;
|
||||
msg.calculate_size(calculated_size);
|
||||
|
||||
// Cache frame sizes to avoid repeated virtual calls
|
||||
const uint8_t header_padding = conn->helper_->frame_header_padding();
|
||||
@@ -410,7 +425,8 @@ uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *con
|
||||
msg.supports_speed = traits.supports_speed();
|
||||
msg.supports_direction = traits.supports_direction();
|
||||
msg.supported_speed_count = traits.supported_speed_count();
|
||||
msg.supported_preset_modes = &traits.supported_preset_modes_for_api_();
|
||||
for (auto const &preset : traits.supported_preset_modes())
|
||||
msg.supported_preset_modes.push_back(preset);
|
||||
return fill_and_encode_entity_info(fan, msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
|
||||
}
|
||||
void APIConnection::fan_command(const FanCommandRequest &msg) {
|
||||
@@ -466,7 +482,8 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c
|
||||
auto *light = static_cast<light::LightState *>(entity);
|
||||
ListEntitiesLightResponse msg;
|
||||
auto traits = light->get_traits();
|
||||
msg.supported_color_modes = &traits.get_supported_color_modes_for_api_();
|
||||
for (auto mode : traits.get_supported_color_modes())
|
||||
msg.supported_color_modes.push_back(static_cast<enums::ColorMode>(mode));
|
||||
if (traits.supports_color_capability(light::ColorCapability::COLOR_TEMPERATURE) ||
|
||||
traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE)) {
|
||||
msg.min_mireds = traits.get_min_mireds();
|
||||
@@ -626,13 +643,17 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection
|
||||
if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
|
||||
resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode.value());
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value()) {
|
||||
resp.set_custom_fan_mode(StringRef(climate->custom_fan_mode.value()));
|
||||
// custom_fan_mode.value() returns temporary - must store it
|
||||
std::string custom_fan_mode = climate->custom_fan_mode.value();
|
||||
resp.set_custom_fan_mode(StringRef(custom_fan_mode));
|
||||
}
|
||||
if (traits.get_supports_presets() && climate->preset.has_value()) {
|
||||
resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value()) {
|
||||
resp.set_custom_preset(StringRef(climate->custom_preset.value()));
|
||||
// custom_preset.value() returns temporary - must store it
|
||||
std::string custom_preset = climate->custom_preset.value();
|
||||
resp.set_custom_preset(StringRef(custom_preset));
|
||||
}
|
||||
if (traits.get_supports_swing_modes())
|
||||
resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
|
||||
@@ -652,7 +673,8 @@ uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection
|
||||
msg.supports_current_humidity = traits.get_supports_current_humidity();
|
||||
msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
|
||||
msg.supports_target_humidity = traits.get_supports_target_humidity();
|
||||
msg.supported_modes = &traits.get_supported_modes_for_api_();
|
||||
for (auto mode : traits.get_supported_modes())
|
||||
msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
|
||||
msg.visual_min_temperature = traits.get_visual_min_temperature();
|
||||
msg.visual_max_temperature = traits.get_visual_max_temperature();
|
||||
msg.visual_target_temperature_step = traits.get_visual_target_temperature_step();
|
||||
@@ -660,11 +682,16 @@ uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection
|
||||
msg.visual_min_humidity = traits.get_visual_min_humidity();
|
||||
msg.visual_max_humidity = traits.get_visual_max_humidity();
|
||||
msg.supports_action = traits.get_supports_action();
|
||||
msg.supported_fan_modes = &traits.get_supported_fan_modes_for_api_();
|
||||
msg.supported_custom_fan_modes = &traits.get_supported_custom_fan_modes_for_api_();
|
||||
msg.supported_presets = &traits.get_supported_presets_for_api_();
|
||||
msg.supported_custom_presets = &traits.get_supported_custom_presets_for_api_();
|
||||
msg.supported_swing_modes = &traits.get_supported_swing_modes_for_api_();
|
||||
for (auto fan_mode : traits.get_supported_fan_modes())
|
||||
msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
|
||||
for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
|
||||
msg.supported_custom_fan_modes.push_back(custom_fan_mode);
|
||||
for (auto preset : traits.get_supported_presets())
|
||||
msg.supported_presets.push_back(static_cast<enums::ClimatePreset>(preset));
|
||||
for (auto const &custom_preset : traits.get_supported_custom_presets())
|
||||
msg.supported_custom_presets.push_back(custom_preset);
|
||||
for (auto swing_mode : traits.get_supported_swing_modes())
|
||||
msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
|
||||
return fill_and_encode_entity_info(climate, msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size,
|
||||
is_single);
|
||||
}
|
||||
@@ -870,7 +897,8 @@ uint16_t APIConnection::try_send_select_info(EntityBase *entity, APIConnection *
|
||||
bool is_single) {
|
||||
auto *select = static_cast<select::Select *>(entity);
|
||||
ListEntitiesSelectResponse msg;
|
||||
msg.options = &select->traits.get_options();
|
||||
for (const auto &option : select->traits.get_options())
|
||||
msg.options.push_back(option);
|
||||
return fill_and_encode_entity_info(select, msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size,
|
||||
is_single);
|
||||
}
|
||||
@@ -996,7 +1024,6 @@ uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnec
|
||||
ListEntitiesMediaPlayerResponse msg;
|
||||
auto traits = media_player->get_traits();
|
||||
msg.supports_pause = traits.get_supports_pause();
|
||||
msg.feature_flags = traits.get_feature_flags();
|
||||
for (auto &supported_format : traits.get_supported_formats()) {
|
||||
msg.supported_formats.emplace_back();
|
||||
auto &media_format = msg.supported_formats.back();
|
||||
@@ -1105,8 +1132,10 @@ void APIConnection::bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg)
|
||||
|
||||
bool APIConnection::send_subscribe_bluetooth_connections_free_response(
|
||||
const SubscribeBluetoothConnectionsFreeRequest &msg) {
|
||||
bluetooth_proxy::global_bluetooth_proxy->send_connections_free(this);
|
||||
return true;
|
||||
BluetoothConnectionsFreeResponse resp;
|
||||
resp.free = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_free();
|
||||
resp.limit = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_limit();
|
||||
return this->send_message(resp, BluetoothConnectionsFreeResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
void APIConnection::bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) {
|
||||
@@ -1183,7 +1212,9 @@ bool APIConnection::send_voice_assistant_get_configuration_response(const VoiceA
|
||||
resp_wake_word.trained_languages.push_back(lang);
|
||||
}
|
||||
}
|
||||
resp.active_wake_words = &config.active_wake_words;
|
||||
for (auto &wake_word_id : config.active_wake_words) {
|
||||
resp.active_wake_words.push_back(wake_word_id);
|
||||
}
|
||||
resp.max_active_wake_words = config.max_active_wake_words;
|
||||
return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
|
||||
}
|
||||
@@ -1361,7 +1392,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
||||
|
||||
HelloResponse resp;
|
||||
resp.api_version_major = 1;
|
||||
resp.api_version_minor = 12;
|
||||
resp.api_version_minor = 10;
|
||||
// Temporary string for concatenation - will be valid during send_message call
|
||||
std::string server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
|
||||
resp.set_server_info(StringRef(server_info));
|
||||
@@ -1462,22 +1493,18 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
|
||||
resp.api_encryption_supported = true;
|
||||
#endif
|
||||
#ifdef USE_DEVICES
|
||||
size_t device_index = 0;
|
||||
for (auto const &device : App.get_devices()) {
|
||||
if (device_index >= ESPHOME_DEVICE_COUNT)
|
||||
break;
|
||||
auto &device_info = resp.devices[device_index++];
|
||||
resp.devices.emplace_back();
|
||||
auto &device_info = resp.devices.back();
|
||||
device_info.device_id = device->get_device_id();
|
||||
device_info.set_name(StringRef(device->get_name()));
|
||||
device_info.area_id = device->get_area_id();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
size_t area_index = 0;
|
||||
for (auto const &area : App.get_areas()) {
|
||||
if (area_index >= ESPHOME_AREA_COUNT)
|
||||
break;
|
||||
auto &area_info = resp.areas[area_index++];
|
||||
resp.areas.emplace_back();
|
||||
auto &area_info = resp.areas.back();
|
||||
area_info.area_id = area->get_area_id();
|
||||
area_info.set_name(StringRef(area->get_name()));
|
||||
}
|
||||
@@ -1486,7 +1513,6 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
|
||||
return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
|
||||
for (auto &it : this->parent_->get_state_subs()) {
|
||||
if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
|
||||
@@ -1494,7 +1520,6 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_SERVICES
|
||||
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
||||
bool found = false;
|
||||
@@ -1510,26 +1535,25 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
||||
#endif
|
||||
#ifdef USE_API_NOISE
|
||||
bool APIConnection::send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) {
|
||||
NoiseEncryptionSetKeyResponse resp;
|
||||
resp.success = false;
|
||||
|
||||
psk_t psk{};
|
||||
NoiseEncryptionSetKeyResponse resp;
|
||||
if (base64_decode(msg.key, psk.data(), msg.key.size()) != psk.size()) {
|
||||
ESP_LOGW(TAG, "Invalid encryption key length");
|
||||
} else if (!this->parent_->save_noise_psk(psk, true)) {
|
||||
ESP_LOGW(TAG, "Failed to save encryption key");
|
||||
} else {
|
||||
resp.success = true;
|
||||
resp.success = false;
|
||||
return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
if (!this->parent_->save_noise_psk(psk, true)) {
|
||||
ESP_LOGW(TAG, "Failed to save encryption key");
|
||||
resp.success = false;
|
||||
return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE);
|
||||
}
|
||||
resp.success = true;
|
||||
return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) {
|
||||
state_subs_at_ = 0;
|
||||
}
|
||||
#endif
|
||||
bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
|
||||
if (this->flags_.remove)
|
||||
return false;
|
||||
@@ -1539,7 +1563,8 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
|
||||
APIError err = this->helper_->loop();
|
||||
if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
this->log_socket_operation_failed_(err);
|
||||
ESP_LOGW(TAG, "%s: Socket operation failed %s errno=%d", this->get_client_combined_info().c_str(),
|
||||
api_error_to_str(err), errno);
|
||||
return false;
|
||||
}
|
||||
if (this->helper_->can_write_without_blocking())
|
||||
@@ -1559,18 +1584,17 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
|
||||
return false;
|
||||
if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
this->log_warning_("Packet write failed", err);
|
||||
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->get_client_combined_info().c_str(),
|
||||
api_error_to_str(err), errno);
|
||||
return false;
|
||||
}
|
||||
// Do not set last_traffic_ on send
|
||||
return true;
|
||||
}
|
||||
#ifdef USE_API_PASSWORD
|
||||
void APIConnection::on_unauthenticated_access() {
|
||||
this->on_fatal_error();
|
||||
ESP_LOGD(TAG, "%s access without authentication", this->get_client_combined_info().c_str());
|
||||
}
|
||||
#endif
|
||||
void APIConnection::on_no_setup_connection() {
|
||||
this->on_fatal_error();
|
||||
ESP_LOGD(TAG, "%s access without full connection", this->get_client_combined_info().c_str());
|
||||
@@ -1644,8 +1668,6 @@ void APIConnection::process_batch_() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get shared buffer reference once to avoid multiple calls
|
||||
auto &shared_buf = this->parent_->get_shared_buffer_ref();
|
||||
size_t num_items = this->deferred_batch_.size();
|
||||
|
||||
// Fast path for single message - allocate exact size needed
|
||||
@@ -1656,7 +1678,8 @@ void APIConnection::process_batch_() {
|
||||
uint16_t payload_size =
|
||||
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
|
||||
|
||||
if (payload_size > 0 && this->send_buffer(ProtoWriteBuffer{&shared_buf}, item.message_type)) {
|
||||
if (payload_size > 0 &&
|
||||
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
// Log messages after send attempt for VV debugging
|
||||
// It's safe to use the buffer for logging at this point regardless of send result
|
||||
@@ -1683,18 +1706,20 @@ void APIConnection::process_batch_() {
|
||||
const uint8_t footer_size = this->helper_->frame_footer_size();
|
||||
|
||||
// Initialize buffer and tracking variables
|
||||
shared_buf.clear();
|
||||
this->parent_->get_shared_buffer_ref().clear();
|
||||
|
||||
// Pre-calculate exact buffer size needed based on message types
|
||||
uint32_t total_estimated_size = num_items * (header_padding + footer_size);
|
||||
uint32_t total_estimated_size = 0;
|
||||
for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
|
||||
const auto &item = this->deferred_batch_[i];
|
||||
total_estimated_size += item.estimated_size;
|
||||
}
|
||||
|
||||
// Calculate total overhead for all messages
|
||||
uint32_t total_overhead = (header_padding + footer_size) * num_items;
|
||||
|
||||
// Reserve based on estimated size (much more accurate than 24-byte worst-case)
|
||||
shared_buf.reserve(total_estimated_size);
|
||||
this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead);
|
||||
this->flags_.batch_first_message = true;
|
||||
|
||||
size_t items_processed = 0;
|
||||
@@ -1736,7 +1761,7 @@ void APIConnection::process_batch_() {
|
||||
remaining_size -= payload_size;
|
||||
// Calculate where the next message's header padding will start
|
||||
// Current buffer size + footer space (that prepare_message_buffer will add for this message)
|
||||
current_offset = shared_buf.size() + footer_size;
|
||||
current_offset = this->parent_->get_shared_buffer_ref().size() + footer_size;
|
||||
}
|
||||
|
||||
if (items_processed == 0) {
|
||||
@@ -1746,15 +1771,17 @@ void APIConnection::process_batch_() {
|
||||
|
||||
// Add footer space for the last message (for Noise protocol MAC)
|
||||
if (footer_size > 0) {
|
||||
auto &shared_buf = this->parent_->get_shared_buffer_ref();
|
||||
shared_buf.resize(shared_buf.size() + footer_size);
|
||||
}
|
||||
|
||||
// Send all collected packets
|
||||
APIError err = this->helper_->write_protobuf_packets(ProtoWriteBuffer{&shared_buf},
|
||||
APIError err = this->helper_->write_protobuf_packets(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()},
|
||||
std::span<const PacketInfo>(packet_info, packet_count));
|
||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||
on_fatal_error();
|
||||
this->log_warning_("Batch write failed", err);
|
||||
ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->get_client_combined_info().c_str(), api_error_to_str(err),
|
||||
errno);
|
||||
}
|
||||
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
@@ -1810,33 +1837,6 @@ uint16_t APIConnection::try_send_ping_request(EntityBase *entity, APIConnection
|
||||
return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
|
||||
}
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void APIConnection::process_state_subscriptions_() {
|
||||
const auto &subs = this->parent_->get_state_subs();
|
||||
if (this->state_subs_at_ >= static_cast<int>(subs.size())) {
|
||||
this->state_subs_at_ = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &it = subs[this->state_subs_at_];
|
||||
SubscribeHomeAssistantStateResponse resp;
|
||||
resp.set_entity_id(StringRef(it.entity_id));
|
||||
|
||||
// Avoid string copy by directly using the optional's value if it exists
|
||||
resp.set_attribute(it.attribute.has_value() ? StringRef(it.attribute.value()) : StringRef(""));
|
||||
|
||||
resp.once = it.once;
|
||||
if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
|
||||
this->state_subs_at_++;
|
||||
}
|
||||
}
|
||||
#endif // USE_API_HOMEASSISTANT_STATES
|
||||
|
||||
void APIConnection::log_warning_(const char *message, APIError err) {
|
||||
ESP_LOGW(TAG, "%s: %s %s errno=%d", this->get_client_combined_info().c_str(), message, api_error_to_str(err), errno);
|
||||
}
|
||||
|
||||
void APIConnection::log_socket_operation_failed_(APIError err) { this->log_warning_("Socket operation failed", err); }
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -13,7 +13,8 @@
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Client information structure
|
||||
struct ClientInfo {
|
||||
@@ -131,13 +132,11 @@ class APIConnection : public APIServerConnection {
|
||||
void media_player_command(const MediaPlayerCommandRequest &msg) override;
|
||||
#endif
|
||||
bool try_send_log_message(int level, const char *tag, const char *line, size_t message_len);
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
||||
if (!this->flags_.service_call_subscription)
|
||||
return;
|
||||
this->send_message(call, HomeassistantServiceResponse::MESSAGE_TYPE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
|
||||
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
|
||||
@@ -190,9 +189,7 @@ class APIConnection : public APIServerConnection {
|
||||
// we initiated ping
|
||||
this->flags_.sent_ping = false;
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override;
|
||||
#endif
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
void on_get_time_response(const GetTimeResponse &value) override;
|
||||
#endif
|
||||
@@ -211,14 +208,10 @@ class APIConnection : public APIServerConnection {
|
||||
if (msg.dump_config)
|
||||
App.schedule_dump_config();
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override {
|
||||
this->flags_.service_call_subscription = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
|
||||
#endif
|
||||
bool send_get_time_response(const GetTimeRequest &msg) override;
|
||||
#ifdef USE_API_SERVICES
|
||||
void execute_service(const ExecuteServiceRequest &msg) override;
|
||||
@@ -235,17 +228,8 @@ class APIConnection : public APIServerConnection {
|
||||
this->is_authenticated();
|
||||
}
|
||||
uint8_t get_log_subscription_level() const { return this->flags_.log_subscription; }
|
||||
|
||||
// Get client API version for feature detection
|
||||
bool client_supports_api_version(uint16_t major, uint16_t minor) const {
|
||||
return this->client_api_version_major_ > major ||
|
||||
(this->client_api_version_major_ == major && this->client_api_version_minor_ >= minor);
|
||||
}
|
||||
|
||||
void on_fatal_error() override;
|
||||
#ifdef USE_API_PASSWORD
|
||||
void on_unauthenticated_access() override;
|
||||
#endif
|
||||
void on_no_setup_connection() override;
|
||||
ProtoWriteBuffer create_buffer(uint32_t reserve_size) override {
|
||||
// FIXME: ensure no recursive writes can happen
|
||||
@@ -305,10 +289,6 @@ class APIConnection : public APIServerConnection {
|
||||
// Helper function to handle authentication completion
|
||||
void complete_authentication_();
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void process_state_subscriptions_();
|
||||
#endif
|
||||
|
||||
// Non-template helper to encode any ProtoMessage
|
||||
static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint8_t message_type, APIConnection *conn,
|
||||
uint32_t remaining_size, bool is_single);
|
||||
@@ -513,9 +493,7 @@ class APIConnection : public APIServerConnection {
|
||||
|
||||
// Group 4: 4-byte types
|
||||
uint32_t last_traffic_;
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
int state_subs_at_ = -1;
|
||||
#endif
|
||||
|
||||
// Function pointer type for message encoding
|
||||
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
|
||||
@@ -703,16 +681,10 @@ class APIConnection : public APIServerConnection {
|
||||
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type,
|
||||
uint8_t estimated_size) {
|
||||
// Try to send immediately if:
|
||||
// 1. It's an UpdateStateResponse (always send immediately to handle cases where
|
||||
// the main loop is blocked, e.g., during OTA updates)
|
||||
// 2. OR: We should try to send immediately (should_try_send_immediately = true)
|
||||
// AND Batch delay is 0 (user has opted in to immediate sending)
|
||||
// 3. AND: Buffer has space available
|
||||
if ((
|
||||
#ifdef USE_UPDATE
|
||||
message_type == UpdateStateResponse::MESSAGE_TYPE ||
|
||||
#endif
|
||||
(this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0)) &&
|
||||
// 1. We should try to send immediately (should_try_send_immediately = true)
|
||||
// 2. Batch delay is 0 (user has opted in to immediate sending)
|
||||
// 3. Buffer has space available
|
||||
if (this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0 &&
|
||||
this->helper_->can_write_without_blocking()) {
|
||||
// Now actually encode and send
|
||||
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true) &&
|
||||
@@ -749,12 +721,8 @@ class APIConnection : public APIServerConnection {
|
||||
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type, estimated_size);
|
||||
return this->schedule_batch_();
|
||||
}
|
||||
|
||||
// Helper function to log API errors with errno
|
||||
void log_warning_(const char *message, APIError err);
|
||||
// Specific helper for duplicated error message
|
||||
void log_socket_operation_failed_(APIError err);
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -9,7 +9,8 @@
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api.frame_helper";
|
||||
|
||||
@@ -246,5 +247,6 @@ APIError APIFrameHelper::handle_socket_read_result_(ssize_t received) {
|
||||
return APIError::OK;
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -12,7 +12,8 @@
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// uncomment to log raw packets
|
||||
//#define HELPER_LOG_PACKETS
|
||||
@@ -183,6 +184,7 @@ class APIFrameHelper {
|
||||
APIError handle_socket_read_result_(ssize_t received);
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_API
|
||||
|
@@ -10,7 +10,8 @@
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api.noise";
|
||||
static const char *const PROLOGUE_INIT = "NoiseAPIInit";
|
||||
@@ -578,6 +579,7 @@ void noise_rand_bytes(void *output, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif // USE_API_NOISE
|
||||
#endif // USE_API
|
||||
|
@@ -5,7 +5,8 @@
|
||||
#include "noise/protocol.h"
|
||||
#include "api_noise_context.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APINoiseFrameHelper : public APIFrameHelper {
|
||||
public:
|
||||
@@ -63,6 +64,7 @@ class APINoiseFrameHelper : public APIFrameHelper {
|
||||
// 4 bytes total, no padding
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif // USE_API_NOISE
|
||||
#endif // USE_API
|
||||
|
@@ -10,7 +10,8 @@
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api.plaintext";
|
||||
|
||||
@@ -285,6 +286,7 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
|
||||
return write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size(), total_write_len);
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif // USE_API_PLAINTEXT
|
||||
#endif // USE_API
|
||||
|
@@ -3,7 +3,8 @@
|
||||
#ifdef USE_API
|
||||
#ifdef USE_API_PLAINTEXT
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIPlaintextFrameHelper : public APIFrameHelper {
|
||||
public:
|
||||
@@ -48,6 +49,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
|
||||
// 8 bytes total, no padding needed
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif // USE_API_PLAINTEXT
|
||||
#endif // USE_API
|
||||
|
@@ -3,7 +3,8 @@
|
||||
#include <cstdint>
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
using psk_t = std::array<uint8_t, 32>;
|
||||
@@ -27,4 +28,5 @@ class APINoiseContext {
|
||||
};
|
||||
#endif // USE_API_NOISE
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -27,33 +27,4 @@ extend google.protobuf.MessageOptions {
|
||||
extend google.protobuf.FieldOptions {
|
||||
optional string field_ifdef = 1042;
|
||||
optional uint32 fixed_array_size = 50007;
|
||||
optional bool no_zero_copy = 50008 [default=false];
|
||||
optional bool fixed_array_skip_zero = 50009 [default=false];
|
||||
optional string fixed_array_size_define = 50010;
|
||||
|
||||
// container_pointer: Zero-copy optimization for repeated fields.
|
||||
//
|
||||
// When container_pointer is set on a repeated field, the generated message will
|
||||
// store a pointer to an existing container instead of copying the data into the
|
||||
// message's own repeated field. This eliminates heap allocations and improves performance.
|
||||
//
|
||||
// Requirements for safe usage:
|
||||
// 1. The source container must remain valid until the message is encoded
|
||||
// 2. Messages must be encoded immediately (which ESPHome does by default)
|
||||
// 3. The container type must match the field type exactly
|
||||
//
|
||||
// Supported container types:
|
||||
// - "std::vector<T>" for most repeated fields
|
||||
// - "std::set<T>" for unique/sorted data
|
||||
// - Full type specification required for enums (e.g., "std::set<climate::ClimateMode>")
|
||||
//
|
||||
// Example usage in .proto file:
|
||||
// repeated string supported_modes = 12 [(container_pointer) = "std::set"];
|
||||
// repeated ColorMode color_modes = 13 [(container_pointer) = "std::set<light::ColorMode>"];
|
||||
//
|
||||
// The corresponding C++ code must provide const reference access to a container
|
||||
// that matches the specified type and remains valid during message encoding.
|
||||
// This is typically done through methods returning const T& or special accessor
|
||||
// methods like get_options() or supported_modes_for_api_().
|
||||
optional string container_pointer = 50001;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,9 +6,9 @@
|
||||
#include "esphome/core/string_ref.h"
|
||||
|
||||
#include "proto.h"
|
||||
#include "api_pb2_includes.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
namespace enums {
|
||||
|
||||
@@ -150,9 +150,6 @@ enum MediaPlayerState : uint32_t {
|
||||
MEDIA_PLAYER_STATE_IDLE = 1,
|
||||
MEDIA_PLAYER_STATE_PLAYING = 2,
|
||||
MEDIA_PLAYER_STATE_PAUSED = 3,
|
||||
MEDIA_PLAYER_STATE_ANNOUNCING = 4,
|
||||
MEDIA_PLAYER_STATE_OFF = 5,
|
||||
MEDIA_PLAYER_STATE_ON = 6,
|
||||
};
|
||||
enum MediaPlayerCommand : uint32_t {
|
||||
MEDIA_PLAYER_COMMAND_PLAY = 0,
|
||||
@@ -160,15 +157,6 @@ enum MediaPlayerCommand : uint32_t {
|
||||
MEDIA_PLAYER_COMMAND_STOP = 2,
|
||||
MEDIA_PLAYER_COMMAND_MUTE = 3,
|
||||
MEDIA_PLAYER_COMMAND_UNMUTE = 4,
|
||||
MEDIA_PLAYER_COMMAND_TOGGLE = 5,
|
||||
MEDIA_PLAYER_COMMAND_VOLUME_UP = 6,
|
||||
MEDIA_PLAYER_COMMAND_VOLUME_DOWN = 7,
|
||||
MEDIA_PLAYER_COMMAND_ENQUEUE = 8,
|
||||
MEDIA_PLAYER_COMMAND_REPEAT_ONE = 9,
|
||||
MEDIA_PLAYER_COMMAND_REPEAT_OFF = 10,
|
||||
MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 11,
|
||||
MEDIA_PLAYER_COMMAND_TURN_ON = 12,
|
||||
MEDIA_PLAYER_COMMAND_TURN_OFF = 13,
|
||||
};
|
||||
enum MediaPlayerFormatPurpose : uint32_t {
|
||||
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
|
||||
@@ -353,7 +341,7 @@ class HelloResponse : public ProtoMessage {
|
||||
StringRef name_ref_{};
|
||||
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -384,14 +372,14 @@ class ConnectResponse : public ProtoMessage {
|
||||
#endif
|
||||
bool invalid_password{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
class DisconnectRequest : public ProtoMessage {
|
||||
class DisconnectRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 5;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -404,7 +392,7 @@ class DisconnectRequest : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class DisconnectResponse : public ProtoMessage {
|
||||
class DisconnectResponse : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 6;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -417,7 +405,7 @@ class DisconnectResponse : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class PingRequest : public ProtoMessage {
|
||||
class PingRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 7;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -430,7 +418,7 @@ class PingRequest : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class PingResponse : public ProtoMessage {
|
||||
class PingResponse : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 8;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -443,7 +431,7 @@ class PingResponse : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class DeviceInfoRequest : public ProtoMessage {
|
||||
class DeviceInfoRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 9;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -463,7 +451,7 @@ class AreaInfo : public ProtoMessage {
|
||||
StringRef name_ref_{};
|
||||
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -479,7 +467,7 @@ class DeviceInfo : public ProtoMessage {
|
||||
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
|
||||
uint32_t area_id{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -490,7 +478,7 @@ class DeviceInfo : public ProtoMessage {
|
||||
class DeviceInfoResponse : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 10;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 247;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 211;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "device_info_response"; }
|
||||
#endif
|
||||
@@ -543,23 +531,23 @@ class DeviceInfoResponse : public ProtoMessage {
|
||||
bool api_encryption_supported{false};
|
||||
#endif
|
||||
#ifdef USE_DEVICES
|
||||
std::array<DeviceInfo, ESPHOME_DEVICE_COUNT> devices{};
|
||||
std::vector<DeviceInfo> devices{};
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
std::array<AreaInfo, ESPHOME_AREA_COUNT> areas{};
|
||||
std::vector<AreaInfo> areas{};
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
AreaInfo area{};
|
||||
#endif
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
class ListEntitiesRequest : public ProtoMessage {
|
||||
class ListEntitiesRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 11;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -585,7 +573,7 @@ class ListEntitiesDoneResponse : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class SubscribeStatesRequest : public ProtoMessage {
|
||||
class SubscribeStatesRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 20;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -610,7 +598,7 @@ class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
bool is_status_binary_sensor{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -627,7 +615,7 @@ class BinarySensorStateResponse : public StateResponseProtoMessage {
|
||||
bool state{false};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -650,7 +638,7 @@ class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
bool supports_stop{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -668,7 +656,7 @@ class CoverStateResponse : public StateResponseProtoMessage {
|
||||
float tilt{0.0f};
|
||||
enums::CoverOperation current_operation{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -708,9 +696,9 @@ class ListEntitiesFanResponse : public InfoResponseProtoMessage {
|
||||
bool supports_speed{false};
|
||||
bool supports_direction{false};
|
||||
int32_t supported_speed_count{0};
|
||||
const std::set<std::string> *supported_preset_modes{};
|
||||
std::vector<std::string> supported_preset_modes{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -731,7 +719,7 @@ class FanStateResponse : public StateResponseProtoMessage {
|
||||
StringRef preset_mode_ref_{};
|
||||
void set_preset_mode(const StringRef &ref) { this->preset_mode_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -773,12 +761,12 @@ class ListEntitiesLightResponse : public InfoResponseProtoMessage {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "list_entities_light_response"; }
|
||||
#endif
|
||||
const std::set<light::ColorMode> *supported_color_modes{};
|
||||
std::vector<enums::ColorMode> supported_color_modes{};
|
||||
float min_mireds{0.0f};
|
||||
float max_mireds{0.0f};
|
||||
std::vector<std::string> effects{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -806,7 +794,7 @@ class LightStateResponse : public StateResponseProtoMessage {
|
||||
StringRef effect_ref_{};
|
||||
void set_effect(const StringRef &ref) { this->effect_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -872,7 +860,7 @@ class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
enums::SensorStateClass state_class{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -889,7 +877,7 @@ class SensorStateResponse : public StateResponseProtoMessage {
|
||||
float state{0.0f};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -909,7 +897,7 @@ class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
|
||||
StringRef device_class_ref_{};
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -925,7 +913,7 @@ class SwitchStateResponse : public StateResponseProtoMessage {
|
||||
#endif
|
||||
bool state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -960,7 +948,7 @@ class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
|
||||
StringRef device_class_ref_{};
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -978,7 +966,7 @@ class TextSensorStateResponse : public StateResponseProtoMessage {
|
||||
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1017,7 +1005,7 @@ class SubscribeLogsResponse : public ProtoMessage {
|
||||
this->message_len_ = len;
|
||||
}
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1049,7 +1037,7 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage {
|
||||
#endif
|
||||
bool success{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1057,8 +1045,7 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage {
|
||||
protected:
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
class SubscribeHomeassistantServicesRequest : public ProtoMessage {
|
||||
class SubscribeHomeassistantServicesRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 34;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -1075,9 +1062,10 @@ class HomeassistantServiceMap : public ProtoMessage {
|
||||
public:
|
||||
StringRef key_ref_{};
|
||||
void set_key(const StringRef &ref) { this->key_ref_ = ref; }
|
||||
std::string value{};
|
||||
StringRef value_ref_{};
|
||||
void set_value(const StringRef &ref) { this->value_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1098,16 +1086,14 @@ class HomeassistantServiceResponse : public ProtoMessage {
|
||||
std::vector<HomeassistantServiceMap> variables{};
|
||||
bool is_event{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
class SubscribeHomeAssistantStatesRequest : public ProtoMessage {
|
||||
class SubscribeHomeAssistantStatesRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 38;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -1133,7 +1119,7 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage {
|
||||
void set_attribute(const StringRef &ref) { this->attribute_ref_ = ref; }
|
||||
bool once{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1157,8 +1143,7 @@ class HomeAssistantStateResponse : public ProtoDecodableMessage {
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
};
|
||||
#endif
|
||||
class GetTimeRequest : public ProtoMessage {
|
||||
class GetTimeRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 36;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -1180,7 +1165,7 @@ class GetTimeResponse : public ProtoDecodableMessage {
|
||||
#endif
|
||||
uint32_t epoch_seconds{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1195,7 +1180,7 @@ class ListEntitiesServicesArgument : public ProtoMessage {
|
||||
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
|
||||
enums::ServiceArgType type{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1214,7 +1199,7 @@ class ListEntitiesServicesResponse : public ProtoMessage {
|
||||
uint32_t key{0};
|
||||
std::vector<ListEntitiesServicesArgument> args{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1268,7 +1253,7 @@ class ListEntitiesCameraResponse : public InfoResponseProtoMessage {
|
||||
const char *message_name() const override { return "list_entities_camera_response"; }
|
||||
#endif
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1290,7 +1275,7 @@ class CameraImageResponse : public StateResponseProtoMessage {
|
||||
}
|
||||
bool done{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1324,23 +1309,23 @@ class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
|
||||
#endif
|
||||
bool supports_current_temperature{false};
|
||||
bool supports_two_point_target_temperature{false};
|
||||
const std::set<climate::ClimateMode> *supported_modes{};
|
||||
std::vector<enums::ClimateMode> supported_modes{};
|
||||
float visual_min_temperature{0.0f};
|
||||
float visual_max_temperature{0.0f};
|
||||
float visual_target_temperature_step{0.0f};
|
||||
bool supports_action{false};
|
||||
const std::set<climate::ClimateFanMode> *supported_fan_modes{};
|
||||
const std::set<climate::ClimateSwingMode> *supported_swing_modes{};
|
||||
const std::set<std::string> *supported_custom_fan_modes{};
|
||||
const std::set<climate::ClimatePreset> *supported_presets{};
|
||||
const std::set<std::string> *supported_custom_presets{};
|
||||
std::vector<enums::ClimateFanMode> supported_fan_modes{};
|
||||
std::vector<enums::ClimateSwingMode> supported_swing_modes{};
|
||||
std::vector<std::string> supported_custom_fan_modes{};
|
||||
std::vector<enums::ClimatePreset> supported_presets{};
|
||||
std::vector<std::string> supported_custom_presets{};
|
||||
float visual_current_temperature_step{0.0f};
|
||||
bool supports_current_humidity{false};
|
||||
bool supports_target_humidity{false};
|
||||
float visual_min_humidity{0.0f};
|
||||
float visual_max_humidity{0.0f};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1370,7 +1355,7 @@ class ClimateStateResponse : public StateResponseProtoMessage {
|
||||
float current_humidity{0.0f};
|
||||
float target_humidity{0.0f};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1431,7 +1416,7 @@ class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
|
||||
StringRef device_class_ref_{};
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1448,7 +1433,7 @@ class NumberStateResponse : public StateResponseProtoMessage {
|
||||
float state{0.0f};
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1480,9 +1465,9 @@ class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "list_entities_select_response"; }
|
||||
#endif
|
||||
const std::vector<std::string> *options{};
|
||||
std::vector<std::string> options{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1500,7 +1485,7 @@ class SelectStateResponse : public StateResponseProtoMessage {
|
||||
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1537,7 +1522,7 @@ class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
|
||||
bool supports_duration{false};
|
||||
bool supports_volume{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1553,7 +1538,7 @@ class SirenStateResponse : public StateResponseProtoMessage {
|
||||
#endif
|
||||
bool state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1599,7 +1584,7 @@ class ListEntitiesLockResponse : public InfoResponseProtoMessage {
|
||||
StringRef code_format_ref_{};
|
||||
void set_code_format(const StringRef &ref) { this->code_format_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1615,7 +1600,7 @@ class LockStateResponse : public StateResponseProtoMessage {
|
||||
#endif
|
||||
enums::LockState state{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1653,7 +1638,7 @@ class ListEntitiesButtonResponse : public InfoResponseProtoMessage {
|
||||
StringRef device_class_ref_{};
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1686,7 +1671,7 @@ class MediaPlayerSupportedFormat : public ProtoMessage {
|
||||
enums::MediaPlayerFormatPurpose purpose{};
|
||||
uint32_t sample_bytes{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1696,15 +1681,14 @@ class MediaPlayerSupportedFormat : public ProtoMessage {
|
||||
class ListEntitiesMediaPlayerResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 63;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 80;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 76;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "list_entities_media_player_response"; }
|
||||
#endif
|
||||
bool supports_pause{false};
|
||||
std::vector<MediaPlayerSupportedFormat> supported_formats{};
|
||||
uint32_t feature_flags{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1722,7 +1706,7 @@ class MediaPlayerStateResponse : public StateResponseProtoMessage {
|
||||
float volume{0.0f};
|
||||
bool muted{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1778,7 +1762,7 @@ class BluetoothLERawAdvertisement : public ProtoMessage {
|
||||
uint8_t data[62]{};
|
||||
uint8_t data_len{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1794,7 +1778,7 @@ class BluetoothLERawAdvertisementsResponse : public ProtoMessage {
|
||||
#endif
|
||||
std::vector<BluetoothLERawAdvertisement> advertisements{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1831,7 +1815,7 @@ class BluetoothDeviceConnectionResponse : public ProtoMessage {
|
||||
uint32_t mtu{0};
|
||||
int32_t error{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1857,9 +1841,8 @@ class BluetoothGATTDescriptor : public ProtoMessage {
|
||||
public:
|
||||
std::array<uint64_t, 2> uuid{};
|
||||
uint32_t handle{0};
|
||||
uint32_t short_uuid{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1872,9 +1855,8 @@ class BluetoothGATTCharacteristic : public ProtoMessage {
|
||||
uint32_t handle{0};
|
||||
uint32_t properties{0};
|
||||
std::vector<BluetoothGATTDescriptor> descriptors{};
|
||||
uint32_t short_uuid{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1886,9 +1868,8 @@ class BluetoothGATTService : public ProtoMessage {
|
||||
std::array<uint64_t, 2> uuid{};
|
||||
uint32_t handle{0};
|
||||
std::vector<BluetoothGATTCharacteristic> characteristics{};
|
||||
uint32_t short_uuid{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1898,14 +1879,14 @@ class BluetoothGATTService : public ProtoMessage {
|
||||
class BluetoothGATTGetServicesResponse : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 71;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 38;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 21;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_gatt_get_services_response"; }
|
||||
#endif
|
||||
uint64_t address{0};
|
||||
std::vector<BluetoothGATTService> services{};
|
||||
std::array<BluetoothGATTService, 1> services{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1921,7 +1902,7 @@ class BluetoothGATTGetServicesDoneResponse : public ProtoMessage {
|
||||
#endif
|
||||
uint64_t address{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -1960,7 +1941,7 @@ class BluetoothGATTReadResponse : public ProtoMessage {
|
||||
this->data_len_ = len;
|
||||
}
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2053,14 +2034,14 @@ class BluetoothGATTNotifyDataResponse : public ProtoMessage {
|
||||
this->data_len_ = len;
|
||||
}
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage {
|
||||
class SubscribeBluetoothConnectionsFreeRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 80;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -2076,15 +2057,15 @@ class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage {
|
||||
class BluetoothConnectionsFreeResponse : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 81;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 20;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 16;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_connections_free_response"; }
|
||||
#endif
|
||||
uint32_t free{0};
|
||||
uint32_t limit{0};
|
||||
std::array<uint64_t, BLUETOOTH_PROXY_MAX_CONNECTIONS> allocated{};
|
||||
std::vector<uint64_t> allocated{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2102,7 +2083,7 @@ class BluetoothGATTErrorResponse : public ProtoMessage {
|
||||
uint32_t handle{0};
|
||||
int32_t error{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2119,7 +2100,7 @@ class BluetoothGATTWriteResponse : public ProtoMessage {
|
||||
uint64_t address{0};
|
||||
uint32_t handle{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2136,7 +2117,7 @@ class BluetoothGATTNotifyResponse : public ProtoMessage {
|
||||
uint64_t address{0};
|
||||
uint32_t handle{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2154,7 +2135,7 @@ class BluetoothDevicePairingResponse : public ProtoMessage {
|
||||
bool paired{false};
|
||||
int32_t error{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2172,14 +2153,14 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage {
|
||||
bool success{false};
|
||||
int32_t error{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
|
||||
class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 87;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -2203,7 +2184,7 @@ class BluetoothDeviceClearCacheResponse : public ProtoMessage {
|
||||
bool success{false};
|
||||
int32_t error{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2220,7 +2201,7 @@ class BluetoothScannerStateResponse : public ProtoMessage {
|
||||
enums::BluetoothScannerState state{};
|
||||
enums::BluetoothScannerMode mode{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2266,7 +2247,7 @@ class VoiceAssistantAudioSettings : public ProtoMessage {
|
||||
uint32_t auto_gain{0};
|
||||
float volume_multiplier{0.0f};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2288,7 +2269,7 @@ class VoiceAssistantRequest : public ProtoMessage {
|
||||
StringRef wake_word_phrase_ref_{};
|
||||
void set_wake_word_phrase(const StringRef &ref) { this->wake_word_phrase_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2355,7 +2336,7 @@ class VoiceAssistantAudio : public ProtoDecodableMessage {
|
||||
}
|
||||
bool end{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2413,7 +2394,7 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage {
|
||||
#endif
|
||||
bool success{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2428,14 +2409,14 @@ class VoiceAssistantWakeWord : public ProtoMessage {
|
||||
void set_wake_word(const StringRef &ref) { this->wake_word_ref_ = ref; }
|
||||
std::vector<std::string> trained_languages{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
};
|
||||
class VoiceAssistantConfigurationRequest : public ProtoMessage {
|
||||
class VoiceAssistantConfigurationRequest : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 121;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 0;
|
||||
@@ -2456,10 +2437,10 @@ class VoiceAssistantConfigurationResponse : public ProtoMessage {
|
||||
const char *message_name() const override { return "voice_assistant_configuration_response"; }
|
||||
#endif
|
||||
std::vector<VoiceAssistantWakeWord> available_wake_words{};
|
||||
const std::vector<std::string> *active_wake_words{};
|
||||
std::vector<std::string> active_wake_words{};
|
||||
uint32_t max_active_wake_words{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2494,7 +2475,7 @@ class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
|
||||
bool requires_code{false};
|
||||
bool requires_code_to_arm{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2510,7 +2491,7 @@ class AlarmControlPanelStateResponse : public StateResponseProtoMessage {
|
||||
#endif
|
||||
enums::AlarmControlPanelState state{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2550,7 +2531,7 @@ class ListEntitiesTextResponse : public InfoResponseProtoMessage {
|
||||
void set_pattern(const StringRef &ref) { this->pattern_ref_ = ref; }
|
||||
enums::TextMode mode{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2568,7 +2549,7 @@ class TextStateResponse : public StateResponseProtoMessage {
|
||||
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
|
||||
bool missing_state{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2602,7 +2583,7 @@ class ListEntitiesDateResponse : public InfoResponseProtoMessage {
|
||||
const char *message_name() const override { return "list_entities_date_response"; }
|
||||
#endif
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2621,7 +2602,7 @@ class DateStateResponse : public StateResponseProtoMessage {
|
||||
uint32_t month{0};
|
||||
uint32_t day{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2656,7 +2637,7 @@ class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
|
||||
const char *message_name() const override { return "list_entities_time_response"; }
|
||||
#endif
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2675,7 +2656,7 @@ class TimeStateResponse : public StateResponseProtoMessage {
|
||||
uint32_t minute{0};
|
||||
uint32_t second{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2713,7 +2694,7 @@ class ListEntitiesEventResponse : public InfoResponseProtoMessage {
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
std::vector<std::string> event_types{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2730,7 +2711,7 @@ class EventResponse : public StateResponseProtoMessage {
|
||||
StringRef event_type_ref_{};
|
||||
void set_event_type(const StringRef &ref) { this->event_type_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2752,7 +2733,7 @@ class ListEntitiesValveResponse : public InfoResponseProtoMessage {
|
||||
bool supports_position{false};
|
||||
bool supports_stop{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2769,7 +2750,7 @@ class ValveStateResponse : public StateResponseProtoMessage {
|
||||
float position{0.0f};
|
||||
enums::ValveOperation current_operation{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2804,7 +2785,7 @@ class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
|
||||
const char *message_name() const override { return "list_entities_date_time_response"; }
|
||||
#endif
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2821,7 +2802,7 @@ class DateTimeStateResponse : public StateResponseProtoMessage {
|
||||
bool missing_state{false};
|
||||
uint32_t epoch_seconds{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2856,7 +2837,7 @@ class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
|
||||
StringRef device_class_ref_{};
|
||||
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2885,7 +2866,7 @@ class UpdateStateResponse : public StateResponseProtoMessage {
|
||||
StringRef release_url_ref_{};
|
||||
void set_release_url(const StringRef &ref) { this->release_url_ref_ = ref; }
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
@@ -2910,4 +2891,5 @@ class UpdateCommandRequest : public CommandProtoMessage {
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -7,7 +7,8 @@
|
||||
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Helper function to append a quoted string, handling empty StringRef
|
||||
static inline void append_quoted_string(std::string &out, const StringRef &ref) {
|
||||
@@ -383,12 +384,6 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::Medi
|
||||
return "MEDIA_PLAYER_STATE_PLAYING";
|
||||
case enums::MEDIA_PLAYER_STATE_PAUSED:
|
||||
return "MEDIA_PLAYER_STATE_PAUSED";
|
||||
case enums::MEDIA_PLAYER_STATE_ANNOUNCING:
|
||||
return "MEDIA_PLAYER_STATE_ANNOUNCING";
|
||||
case enums::MEDIA_PLAYER_STATE_OFF:
|
||||
return "MEDIA_PLAYER_STATE_OFF";
|
||||
case enums::MEDIA_PLAYER_STATE_ON:
|
||||
return "MEDIA_PLAYER_STATE_ON";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -405,24 +400,6 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
|
||||
return "MEDIA_PLAYER_COMMAND_MUTE";
|
||||
case enums::MEDIA_PLAYER_COMMAND_UNMUTE:
|
||||
return "MEDIA_PLAYER_COMMAND_UNMUTE";
|
||||
case enums::MEDIA_PLAYER_COMMAND_TOGGLE:
|
||||
return "MEDIA_PLAYER_COMMAND_TOGGLE";
|
||||
case enums::MEDIA_PLAYER_COMMAND_VOLUME_UP:
|
||||
return "MEDIA_PLAYER_COMMAND_VOLUME_UP";
|
||||
case enums::MEDIA_PLAYER_COMMAND_VOLUME_DOWN:
|
||||
return "MEDIA_PLAYER_COMMAND_VOLUME_DOWN";
|
||||
case enums::MEDIA_PLAYER_COMMAND_ENQUEUE:
|
||||
return "MEDIA_PLAYER_COMMAND_ENQUEUE";
|
||||
case enums::MEDIA_PLAYER_COMMAND_REPEAT_ONE:
|
||||
return "MEDIA_PLAYER_COMMAND_REPEAT_ONE";
|
||||
case enums::MEDIA_PLAYER_COMMAND_REPEAT_OFF:
|
||||
return "MEDIA_PLAYER_COMMAND_REPEAT_OFF";
|
||||
case enums::MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST:
|
||||
return "MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST";
|
||||
case enums::MEDIA_PLAYER_COMMAND_TURN_ON:
|
||||
return "MEDIA_PLAYER_COMMAND_TURN_ON";
|
||||
case enums::MEDIA_PLAYER_COMMAND_TURN_OFF:
|
||||
return "MEDIA_PLAYER_COMMAND_TURN_OFF";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -838,7 +815,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const {
|
||||
dump_field(out, "icon", this->icon_ref_);
|
||||
#endif
|
||||
dump_field(out, "entity_category", static_cast<enums::EntityCategory>(this->entity_category));
|
||||
for (const auto &it : *this->supported_preset_modes) {
|
||||
for (const auto &it : this->supported_preset_modes) {
|
||||
dump_field(out, "supported_preset_modes", it, 4);
|
||||
}
|
||||
#ifdef USE_DEVICES
|
||||
@@ -881,7 +858,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const {
|
||||
dump_field(out, "object_id", this->object_id_ref_);
|
||||
dump_field(out, "key", this->key);
|
||||
dump_field(out, "name", this->name_ref_);
|
||||
for (const auto &it : *this->supported_color_modes) {
|
||||
for (const auto &it : this->supported_color_modes) {
|
||||
dump_field(out, "supported_color_modes", static_cast<enums::ColorMode>(it), 4);
|
||||
}
|
||||
dump_field(out, "min_mireds", this->min_mireds);
|
||||
@@ -1062,14 +1039,13 @@ void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const {
|
||||
}
|
||||
void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { dump_field(out, "success", this->success); }
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const {
|
||||
out.append("SubscribeHomeassistantServicesRequest {}");
|
||||
}
|
||||
void HomeassistantServiceMap::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "HomeassistantServiceMap");
|
||||
dump_field(out, "key", this->key_ref_);
|
||||
dump_field(out, "value", this->value);
|
||||
dump_field(out, "value", this->value_ref_);
|
||||
}
|
||||
void HomeassistantServiceResponse::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "HomeassistantServiceResponse");
|
||||
@@ -1091,8 +1067,6 @@ void HomeassistantServiceResponse::dump_to(std::string &out) const {
|
||||
}
|
||||
dump_field(out, "is_event", this->is_event);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const {
|
||||
out.append("SubscribeHomeAssistantStatesRequest {}");
|
||||
}
|
||||
@@ -1108,7 +1082,6 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const {
|
||||
dump_field(out, "state", this->state);
|
||||
dump_field(out, "attribute", this->attribute);
|
||||
}
|
||||
#endif
|
||||
void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); }
|
||||
void GetTimeResponse::dump_to(std::string &out) const { dump_field(out, "epoch_seconds", this->epoch_seconds); }
|
||||
#ifdef USE_API_SERVICES
|
||||
@@ -1197,26 +1170,26 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
dump_field(out, "name", this->name_ref_);
|
||||
dump_field(out, "supports_current_temperature", this->supports_current_temperature);
|
||||
dump_field(out, "supports_two_point_target_temperature", this->supports_two_point_target_temperature);
|
||||
for (const auto &it : *this->supported_modes) {
|
||||
for (const auto &it : this->supported_modes) {
|
||||
dump_field(out, "supported_modes", static_cast<enums::ClimateMode>(it), 4);
|
||||
}
|
||||
dump_field(out, "visual_min_temperature", this->visual_min_temperature);
|
||||
dump_field(out, "visual_max_temperature", this->visual_max_temperature);
|
||||
dump_field(out, "visual_target_temperature_step", this->visual_target_temperature_step);
|
||||
dump_field(out, "supports_action", this->supports_action);
|
||||
for (const auto &it : *this->supported_fan_modes) {
|
||||
for (const auto &it : this->supported_fan_modes) {
|
||||
dump_field(out, "supported_fan_modes", static_cast<enums::ClimateFanMode>(it), 4);
|
||||
}
|
||||
for (const auto &it : *this->supported_swing_modes) {
|
||||
for (const auto &it : this->supported_swing_modes) {
|
||||
dump_field(out, "supported_swing_modes", static_cast<enums::ClimateSwingMode>(it), 4);
|
||||
}
|
||||
for (const auto &it : *this->supported_custom_fan_modes) {
|
||||
for (const auto &it : this->supported_custom_fan_modes) {
|
||||
dump_field(out, "supported_custom_fan_modes", it, 4);
|
||||
}
|
||||
for (const auto &it : *this->supported_presets) {
|
||||
for (const auto &it : this->supported_presets) {
|
||||
dump_field(out, "supported_presets", static_cast<enums::ClimatePreset>(it), 4);
|
||||
}
|
||||
for (const auto &it : *this->supported_custom_presets) {
|
||||
for (const auto &it : this->supported_custom_presets) {
|
||||
dump_field(out, "supported_custom_presets", it, 4);
|
||||
}
|
||||
dump_field(out, "disabled_by_default", this->disabled_by_default);
|
||||
@@ -1329,7 +1302,7 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const {
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, "icon", this->icon_ref_);
|
||||
#endif
|
||||
for (const auto &it : *this->options) {
|
||||
for (const auto &it : this->options) {
|
||||
dump_field(out, "options", it, 4);
|
||||
}
|
||||
dump_field(out, "disabled_by_default", this->disabled_by_default);
|
||||
@@ -1490,7 +1463,6 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
||||
#ifdef USE_DEVICES
|
||||
dump_field(out, "device_id", this->device_id);
|
||||
#endif
|
||||
dump_field(out, "feature_flags", this->feature_flags);
|
||||
}
|
||||
void MediaPlayerStateResponse::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "MediaPlayerStateResponse");
|
||||
@@ -1561,7 +1533,6 @@ void BluetoothGATTDescriptor::dump_to(std::string &out) const {
|
||||
dump_field(out, "uuid", it, 4);
|
||||
}
|
||||
dump_field(out, "handle", this->handle);
|
||||
dump_field(out, "short_uuid", this->short_uuid);
|
||||
}
|
||||
void BluetoothGATTCharacteristic::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "BluetoothGATTCharacteristic");
|
||||
@@ -1575,7 +1546,6 @@ void BluetoothGATTCharacteristic::dump_to(std::string &out) const {
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
dump_field(out, "short_uuid", this->short_uuid);
|
||||
}
|
||||
void BluetoothGATTService::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "BluetoothGATTService");
|
||||
@@ -1588,7 +1558,6 @@ void BluetoothGATTService::dump_to(std::string &out) const {
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
dump_field(out, "short_uuid", this->short_uuid);
|
||||
}
|
||||
void BluetoothGATTGetServicesResponse::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "BluetoothGATTGetServicesResponse");
|
||||
@@ -1797,7 +1766,7 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const {
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
for (const auto &it : *this->active_wake_words) {
|
||||
for (const auto &it : this->active_wake_words) {
|
||||
dump_field(out, "active_wake_words", it, 4);
|
||||
}
|
||||
dump_field(out, "max_active_wake_words", this->max_active_wake_words);
|
||||
@@ -2098,6 +2067,7 @@ void UpdateCommandRequest::dump_to(std::string &out) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
||||
#endif // HAS_PROTO_MESSAGE_DUMP
|
||||
|
@@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
// This file provides includes needed by the generated protobuf code
|
||||
// when using pointer optimizations for component-specific types
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
#include "esphome/components/climate/climate_mode.h"
|
||||
#include "esphome/components/climate/climate_traits.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#include "esphome/components/light/light_traits.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
#include "esphome/components/fan/fan_traits.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
#include "esphome/components/select/select_traits.h"
|
||||
#endif
|
||||
|
||||
// Standard library includes that might be needed
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace esphome::api {
|
||||
|
||||
// This file only provides includes, no actual code
|
||||
|
||||
} // namespace esphome::api
|
@@ -3,7 +3,8 @@
|
||||
#include "api_pb2_service.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api.service";
|
||||
|
||||
@@ -35,7 +36,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case DisconnectRequest::MESSAGE_TYPE: {
|
||||
DisconnectRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_disconnect_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -44,7 +45,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case DisconnectResponse::MESSAGE_TYPE: {
|
||||
DisconnectResponse msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_disconnect_response: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -53,7 +54,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case PingRequest::MESSAGE_TYPE: {
|
||||
PingRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_ping_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -62,7 +63,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case PingResponse::MESSAGE_TYPE: {
|
||||
PingResponse msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_ping_response: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -71,7 +72,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case DeviceInfoRequest::MESSAGE_TYPE: {
|
||||
DeviceInfoRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_device_info_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -80,7 +81,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case ListEntitiesRequest::MESSAGE_TYPE: {
|
||||
ListEntitiesRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_list_entities_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -89,7 +90,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
}
|
||||
case SubscribeStatesRequest::MESSAGE_TYPE: {
|
||||
SubscribeStatesRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_subscribe_states_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -149,20 +150,18 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
case SubscribeHomeassistantServicesRequest::MESSAGE_TYPE: {
|
||||
SubscribeHomeassistantServicesRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_subscribe_homeassistant_services_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
this->on_subscribe_homeassistant_services_request(msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case GetTimeRequest::MESSAGE_TYPE: {
|
||||
GetTimeRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_get_time_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -178,18 +177,15 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
this->on_get_time_response(msg);
|
||||
break;
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
case SubscribeHomeAssistantStatesRequest::MESSAGE_TYPE: {
|
||||
SubscribeHomeAssistantStatesRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_subscribe_home_assistant_states_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
this->on_subscribe_home_assistant_states_request(msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
case HomeAssistantStateResponse::MESSAGE_TYPE: {
|
||||
HomeAssistantStateResponse msg;
|
||||
msg.decode(msg_data, msg_size);
|
||||
@@ -199,7 +195,6 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
this->on_home_assistant_state_response(msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_SERVICES
|
||||
case ExecuteServiceRequest::MESSAGE_TYPE: {
|
||||
ExecuteServiceRequest msg;
|
||||
@@ -390,7 +385,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
case SubscribeBluetoothConnectionsFreeRequest::MESSAGE_TYPE: {
|
||||
SubscribeBluetoothConnectionsFreeRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -401,7 +396,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
case UnsubscribeBluetoothLEAdvertisementsRequest::MESSAGE_TYPE: {
|
||||
UnsubscribeBluetoothLEAdvertisementsRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -555,7 +550,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
case VoiceAssistantConfigurationRequest::MESSAGE_TYPE: {
|
||||
VoiceAssistantConfigurationRequest msg;
|
||||
// Empty message: no decode needed
|
||||
msg.decode(msg_data, msg_size);
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str());
|
||||
#endif
|
||||
@@ -641,21 +636,17 @@ void APIServerConnection::on_subscribe_logs_request(const SubscribeLogsRequest &
|
||||
this->subscribe_logs(msg);
|
||||
}
|
||||
}
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void APIServerConnection::on_subscribe_homeassistant_services_request(
|
||||
const SubscribeHomeassistantServicesRequest &msg) {
|
||||
if (this->check_authenticated_()) {
|
||||
this->subscribe_homeassistant_services(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void APIServerConnection::on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) {
|
||||
if (this->check_authenticated_()) {
|
||||
this->subscribe_home_assistant_states(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) {
|
||||
if (this->check_connection_setup_() && !this->send_get_time_response(msg)) {
|
||||
this->on_fatal_error();
|
||||
@@ -910,4 +901,5 @@ void APIServerConnection::on_alarm_control_panel_command_request(const AlarmCont
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -6,7 +6,8 @@
|
||||
|
||||
#include "api_pb2.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIServerConnectionBase : public ProtoService {
|
||||
public:
|
||||
@@ -60,17 +61,11 @@ class APIServerConnectionBase : public ProtoService {
|
||||
virtual void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
virtual void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
virtual void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &value){};
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
virtual void on_home_assistant_state_response(const HomeAssistantStateResponse &value){};
|
||||
#endif
|
||||
virtual void on_get_time_request(const GetTimeRequest &value){};
|
||||
virtual void on_get_time_response(const GetTimeResponse &value){};
|
||||
|
||||
@@ -220,12 +215,8 @@ class APIServerConnection : public APIServerConnectionBase {
|
||||
virtual void list_entities(const ListEntitiesRequest &msg) = 0;
|
||||
virtual void subscribe_states(const SubscribeStatesRequest &msg) = 0;
|
||||
virtual void subscribe_logs(const SubscribeLogsRequest &msg) = 0;
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
virtual void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) = 0;
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0;
|
||||
#endif
|
||||
virtual bool send_get_time_response(const GetTimeRequest &msg) = 0;
|
||||
#ifdef USE_API_SERVICES
|
||||
virtual void execute_service(const ExecuteServiceRequest &msg) = 0;
|
||||
@@ -342,12 +333,8 @@ class APIServerConnection : public APIServerConnectionBase {
|
||||
void on_list_entities_request(const ListEntitiesRequest &msg) override;
|
||||
void on_subscribe_states_request(const SubscribeStatesRequest &msg) override;
|
||||
void on_subscribe_logs_request(const SubscribeLogsRequest &msg) override;
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &msg) override;
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) override;
|
||||
#endif
|
||||
void on_get_time_request(const GetTimeRequest &msg) override;
|
||||
#ifdef USE_API_SERVICES
|
||||
void on_execute_service_request(const ExecuteServiceRequest &msg) override;
|
||||
@@ -457,4 +444,5 @@ class APIServerConnection : public APIServerConnectionBase {
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -16,7 +16,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api";
|
||||
|
||||
@@ -369,15 +370,12 @@ void APIServer::set_password(const std::string &password) { this->password_ = pa
|
||||
|
||||
void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
||||
for (auto &client : this->clients_) {
|
||||
client->send_homeassistant_service_call(call);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
||||
@@ -401,7 +399,6 @@ void APIServer::get_home_assistant_state(std::string entity_id, optional<std::st
|
||||
const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
|
||||
return this->state_subs_;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t APIServer::get_port() const { return this->port_; }
|
||||
|
||||
@@ -486,5 +483,6 @@ bool APIServer::teardown() {
|
||||
return this->clients_.empty();
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -18,7 +18,8 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
struct SavedNoisePsk {
|
||||
@@ -106,9 +107,7 @@ class APIServer : public Component, public Controller {
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
void on_media_player_update(media_player::MediaPlayer *obj) override;
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
|
||||
#endif
|
||||
#ifdef USE_API_SERVICES
|
||||
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
|
||||
#endif
|
||||
@@ -128,7 +127,6 @@ class APIServer : public Component, public Controller {
|
||||
|
||||
bool is_connected() const;
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
struct HomeAssistantStateSubscription {
|
||||
std::string entity_id;
|
||||
optional<std::string> attribute;
|
||||
@@ -141,7 +139,6 @@ class APIServer : public Component, public Controller {
|
||||
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f);
|
||||
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
||||
#endif
|
||||
#ifdef USE_API_SERVICES
|
||||
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
|
||||
#endif
|
||||
@@ -175,9 +172,7 @@ class APIServer : public Component, public Controller {
|
||||
std::string password_;
|
||||
#endif
|
||||
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
std::vector<HomeAssistantStateSubscription> state_subs_;
|
||||
#endif
|
||||
#ifdef USE_API_SERVICES
|
||||
std::vector<UserServiceDescriptor *> user_services_;
|
||||
#endif
|
||||
@@ -201,5 +196,6 @@ template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
|
||||
bool check(Ts... x) override { return global_api_server->is_connected(); }
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -14,8 +14,6 @@ with warnings.catch_warnings():
|
||||
from aioesphomeapi import APIClient, parse_log_message
|
||||
from aioesphomeapi.log_runner import async_run
|
||||
|
||||
import contextlib
|
||||
|
||||
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
|
||||
from esphome.core import CORE
|
||||
|
||||
@@ -30,7 +28,7 @@ if TYPE_CHECKING:
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
async def async_run_logs(config: dict[str, Any], address: str) -> None:
|
||||
"""Run the logs command in the event loop."""
|
||||
conf = config["api"]
|
||||
name = config["esphome"]["name"]
|
||||
@@ -39,21 +37,13 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
noise_psk: str | None = None
|
||||
if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
|
||||
noise_psk = key
|
||||
|
||||
if len(addresses) == 1:
|
||||
_LOGGER.info("Starting log output from %s using esphome API", addresses[0])
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"Starting log output from %s using esphome API", " or ".join(addresses)
|
||||
)
|
||||
|
||||
_LOGGER.info("Starting log output from %s using esphome API", address)
|
||||
cli = APIClient(
|
||||
addresses[0], # Primary address for compatibility
|
||||
address,
|
||||
port,
|
||||
password,
|
||||
client_info=f"ESPHome Logs {__version__}",
|
||||
noise_psk=noise_psk,
|
||||
addresses=addresses, # Pass all addresses for automatic retry
|
||||
)
|
||||
dashboard = CORE.dashboard
|
||||
|
||||
@@ -74,7 +64,9 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
await stop()
|
||||
|
||||
|
||||
def run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
def run_logs(config: dict[str, Any], address: str) -> None:
|
||||
"""Run the logs command."""
|
||||
with contextlib.suppress(KeyboardInterrupt):
|
||||
asyncio.run(async_run_logs(config, addresses))
|
||||
try:
|
||||
asyncio.run(async_run_logs(config, address))
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
@@ -6,7 +6,8 @@
|
||||
#ifdef USE_API_SERVICES
|
||||
#include "user_services.h"
|
||||
#endif
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_API_SERVICES
|
||||
template<typename T, typename... Ts> class CustomAPIDeviceService : public UserServiceBase<Ts...> {
|
||||
@@ -56,14 +57,6 @@ class CustomAPIDevice {
|
||||
auto *service = new CustomAPIDeviceService<T, Ts...>(name, arg_names, (T *) this, callback); // NOLINT
|
||||
global_api_server->register_user_service(service);
|
||||
}
|
||||
#else
|
||||
template<typename T, typename... Ts>
|
||||
void register_service(void (T::*callback)(Ts...), const std::string &name,
|
||||
const std::array<std::string, sizeof...(Ts)> &arg_names) {
|
||||
static_assert(
|
||||
sizeof(T) == 0,
|
||||
"register_service() requires 'custom_services: true' in the 'api:' section of your YAML configuration");
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Register a custom native API service that will show up in Home Assistant.
|
||||
@@ -89,15 +82,8 @@ class CustomAPIDevice {
|
||||
auto *service = new CustomAPIDeviceService<T>(name, {}, (T *) this, callback); // NOLINT
|
||||
global_api_server->register_user_service(service);
|
||||
}
|
||||
#else
|
||||
template<typename T> void register_service(void (T::*callback)(), const std::string &name) {
|
||||
static_assert(
|
||||
sizeof(T) == 0,
|
||||
"register_service() requires 'custom_services: true' in the 'api:' section of your YAML configuration");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
/** Subscribe to the state (or attribute state) of an entity from Home Assistant.
|
||||
*
|
||||
* Usage:
|
||||
@@ -149,25 +135,7 @@ class CustomAPIDevice {
|
||||
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
static_assert(sizeof(T) == 0,
|
||||
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
|
||||
"of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
static_assert(sizeof(T) == 0,
|
||||
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
|
||||
"of your YAML configuration");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
/** Call a Home Assistant service from ESPHome.
|
||||
*
|
||||
* Usage:
|
||||
@@ -205,7 +173,7 @@ class CustomAPIDevice {
|
||||
resp.data.emplace_back();
|
||||
auto &kv = resp.data.back();
|
||||
kv.set_key(StringRef(it.first));
|
||||
kv.value = it.second;
|
||||
kv.set_value(StringRef(it.second));
|
||||
}
|
||||
global_api_server->send_homeassistant_service_call(resp);
|
||||
}
|
||||
@@ -248,34 +216,12 @@ class CustomAPIDevice {
|
||||
resp.data.emplace_back();
|
||||
auto &kv = resp.data.back();
|
||||
kv.set_key(StringRef(it.first));
|
||||
kv.value = it.second;
|
||||
kv.set_value(StringRef(it.second));
|
||||
}
|
||||
global_api_server->send_homeassistant_service_call(resp);
|
||||
}
|
||||
#else
|
||||
template<typename T = void> void call_homeassistant_service(const std::string &service_name) {
|
||||
static_assert(sizeof(T) == 0, "call_homeassistant_service() requires 'homeassistant_services: true' in the 'api:' "
|
||||
"section of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T = void>
|
||||
void call_homeassistant_service(const std::string &service_name, const std::map<std::string, std::string> &data) {
|
||||
static_assert(sizeof(T) == 0, "call_homeassistant_service() requires 'homeassistant_services: true' in the 'api:' "
|
||||
"section of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T = void> void fire_homeassistant_event(const std::string &event_name) {
|
||||
static_assert(sizeof(T) == 0, "fire_homeassistant_event() requires 'homeassistant_services: true' in the 'api:' "
|
||||
"section of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T = void>
|
||||
void fire_homeassistant_event(const std::string &service_name, const std::map<std::string, std::string> &data) {
|
||||
static_assert(sizeof(T) == 0, "fire_homeassistant_event() requires 'homeassistant_services: true' in the 'api:' "
|
||||
"section of your YAML configuration");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -2,13 +2,13 @@
|
||||
|
||||
#include "api_server.h"
|
||||
#ifdef USE_API
|
||||
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
||||
#include "api_pb2.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <vector>
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
template<typename... X> class TemplatableStringValue : public TemplatableValue<std::string, X...> {
|
||||
private:
|
||||
@@ -36,9 +36,6 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s
|
||||
|
||||
template<typename... Ts> class TemplatableKeyValuePair {
|
||||
public:
|
||||
// Keys are always string literals from YAML dictionary keys (e.g., "code", "event")
|
||||
// and never templatable values or lambdas. Only the value parameter can be a lambda/template.
|
||||
// Using pass-by-value with std::move allows optimal performance for both lvalues and rvalues.
|
||||
template<typename T> TemplatableKeyValuePair(std::string key, T value) : key(std::move(key)), value(value) {}
|
||||
std::string key;
|
||||
TemplatableStringValue<Ts...> value;
|
||||
@@ -50,16 +47,11 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
|
||||
|
||||
template<typename T> void set_service(T service) { this->service_ = service; }
|
||||
|
||||
// Keys are always string literals from the Python code generation (e.g., cg.add(var.add_data("tag_id", templ))).
|
||||
// The value parameter can be a lambda/template, but keys are never templatable.
|
||||
// Using pass-by-value allows the compiler to optimize for both lvalues and rvalues.
|
||||
template<typename T> void add_data(std::string key, T value) { this->data_.emplace_back(std::move(key), value); }
|
||||
template<typename T> void add_data(std::string key, T value) { this->data_.emplace_back(key, value); }
|
||||
template<typename T> void add_data_template(std::string key, T value) {
|
||||
this->data_template_.emplace_back(std::move(key), value);
|
||||
}
|
||||
template<typename T> void add_variable(std::string key, T value) {
|
||||
this->variables_.emplace_back(std::move(key), value);
|
||||
this->data_template_.emplace_back(key, value);
|
||||
}
|
||||
template<typename T> void add_variable(std::string key, T value) { this->variables_.emplace_back(key, value); }
|
||||
|
||||
void play(Ts... x) override {
|
||||
HomeassistantServiceResponse resp;
|
||||
@@ -70,19 +62,22 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
|
||||
resp.data.emplace_back();
|
||||
auto &kv = resp.data.back();
|
||||
kv.set_key(StringRef(it.key));
|
||||
kv.value = it.value.value(x...);
|
||||
std::string value = it.value.value(x...);
|
||||
kv.set_value(StringRef(value));
|
||||
}
|
||||
for (auto &it : this->data_template_) {
|
||||
resp.data_template.emplace_back();
|
||||
auto &kv = resp.data_template.back();
|
||||
kv.set_key(StringRef(it.key));
|
||||
kv.value = it.value.value(x...);
|
||||
std::string value = it.value.value(x...);
|
||||
kv.set_value(StringRef(value));
|
||||
}
|
||||
for (auto &it : this->variables_) {
|
||||
resp.variables.emplace_back();
|
||||
auto &kv = resp.variables.back();
|
||||
kv.set_key(StringRef(it.key));
|
||||
kv.value = it.value.value(x...);
|
||||
std::string value = it.value.value(x...);
|
||||
kv.set_value(StringRef(value));
|
||||
}
|
||||
this->parent_->send_homeassistant_service_call(resp);
|
||||
}
|
||||
@@ -96,6 +91,6 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
|
||||
std::vector<TemplatableKeyValuePair<Ts...>> variables_;
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
#endif
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -6,7 +6,8 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Generate entity handler implementations using macros
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
@@ -89,5 +90,6 @@ bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -4,7 +4,8 @@
|
||||
#ifdef USE_API
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/component_iterator.h"
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIConnection;
|
||||
|
||||
@@ -95,5 +96,6 @@ class ListEntitiesIterator : public ComponentIterator {
|
||||
APIConnection *client_;
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -3,7 +3,8 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *const TAG = "api.proto";
|
||||
|
||||
@@ -88,4 +89,5 @@ std::string ProtoMessage::dump() const {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -13,7 +13,8 @@
|
||||
#define HAS_PROTO_MESSAGE_DUMP
|
||||
#endif
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
/*
|
||||
* StringRef Ownership Model for API Protocol Messages
|
||||
@@ -35,10 +36,11 @@ namespace esphome::api {
|
||||
*
|
||||
* Unsafe Patterns (WILL cause crashes/corruption):
|
||||
* 1. Temporaries: msg.set_field(StringRef(obj.get_string())) // get_string() returns by value
|
||||
* 2. Concatenation: msg.set_field(StringRef(str1 + str2)) // Result is temporary
|
||||
* 2. Optional values: msg.set_field(StringRef(optional.value())) // value() returns a copy
|
||||
* 3. Concatenation: msg.set_field(StringRef(str1 + str2)) // Result is temporary
|
||||
*
|
||||
* For unsafe patterns, store in a local variable first:
|
||||
* std::string temp = get_string(); // or str1 + str2
|
||||
* std::string temp = optional.value(); // or get_string() or str1 + str2
|
||||
* msg.set_field(StringRef(temp));
|
||||
*
|
||||
* The send_*_response pattern ensures proper lifetime management by encoding
|
||||
@@ -333,16 +335,13 @@ class ProtoWriteBuffer {
|
||||
std::vector<uint8_t> *buffer_;
|
||||
};
|
||||
|
||||
// Forward declaration
|
||||
class ProtoSize;
|
||||
|
||||
class ProtoMessage {
|
||||
public:
|
||||
virtual ~ProtoMessage() = default;
|
||||
// Default implementation for messages with no fields
|
||||
virtual void encode(ProtoWriteBuffer buffer) const {}
|
||||
// Default implementation for messages with no fields
|
||||
virtual void calculate_size(ProtoSize &size) const {}
|
||||
virtual void calculate_size(uint32_t &total_size) const {}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
std::string dump() const;
|
||||
virtual void dump_to(std::string &out) const = 0;
|
||||
@@ -363,32 +362,24 @@ class ProtoDecodableMessage : public ProtoMessage {
|
||||
};
|
||||
|
||||
class ProtoSize {
|
||||
private:
|
||||
uint32_t total_size_ = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief ProtoSize class for Protocol Buffer serialization size calculation
|
||||
*
|
||||
* This class provides methods to calculate the exact byte counts needed
|
||||
* for encoding various Protocol Buffer field types. The class now uses an
|
||||
* object-based approach to reduce parameter passing overhead while keeping
|
||||
* varint calculation methods static for external use.
|
||||
* This class provides static methods to calculate the exact byte counts needed
|
||||
* for encoding various Protocol Buffer field types. All methods are designed to be
|
||||
* efficient for the common case where many fields have default values.
|
||||
*
|
||||
* Implements Protocol Buffer encoding size calculation according to:
|
||||
* https://protobuf.dev/programming-guides/encoding/
|
||||
*
|
||||
* Key features:
|
||||
* - Object-based approach reduces flash usage by eliminating parameter passing
|
||||
* - Early-return optimization for zero/default values
|
||||
* - Static varint methods for external callers
|
||||
* - Direct total_size updates to avoid unnecessary additions
|
||||
* - Specialized handling for different field types according to protobuf spec
|
||||
* - Templated helpers for repeated fields and messages
|
||||
*/
|
||||
|
||||
ProtoSize() = default;
|
||||
|
||||
uint32_t get_size() const { return total_size_; }
|
||||
|
||||
/**
|
||||
* @brief Calculates the size in bytes needed to encode a uint32_t value as a varint
|
||||
*
|
||||
@@ -489,7 +480,9 @@ class ProtoSize {
|
||||
* @brief Common parameters for all add_*_field methods
|
||||
*
|
||||
* All add_*_field methods follow these common patterns:
|
||||
* * @param field_id_size Pre-calculated size of the field ID in bytes
|
||||
*
|
||||
* @param total_size Reference to the total message size to update
|
||||
* @param field_id_size Pre-calculated size of the field ID in bytes
|
||||
* @param value The value to calculate size for (type varies)
|
||||
* @param force Whether to calculate size even if the value is default/zero/empty
|
||||
*
|
||||
@@ -502,63 +495,85 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size
|
||||
*/
|
||||
inline void add_int32(uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
add_int32_force(field_id_size, value);
|
||||
static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
if (value < 0) {
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size += field_id_size + 10;
|
||||
} else {
|
||||
// For non-negative values, use the standard varint size
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_int32_force(uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size when forced
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size_ += field_id_size + (value < 0 ? 10 : varint(static_cast<uint32_t>(value)));
|
||||
static inline void add_int32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
if (value < 0) {
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size += field_id_size + 10;
|
||||
} else {
|
||||
// For non-negative values, use the standard varint size
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size
|
||||
*/
|
||||
inline void add_uint32(uint32_t field_id_size, uint32_t value) {
|
||||
if (value != 0) {
|
||||
add_uint32_force(field_id_size, value);
|
||||
static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_uint32_force(uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
static inline void add_uint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size
|
||||
*/
|
||||
inline void add_bool(uint32_t field_id_size, bool value) {
|
||||
if (value) {
|
||||
// Boolean fields always use 1 byte when true
|
||||
total_size_ += field_id_size + 1;
|
||||
static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
||||
// Skip calculation if value is false
|
||||
if (!value) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Boolean fields always use 1 byte when true
|
||||
total_size += field_id_size + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_bool_force(uint32_t field_id_size, bool value) {
|
||||
// Always calculate size when force is true
|
||||
static inline void add_bool_field_repeated(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
||||
// Always calculate size for repeated fields
|
||||
// Boolean fields always use 1 byte
|
||||
total_size_ += field_id_size + 1;
|
||||
total_size += field_id_size + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a float field to the total message size
|
||||
*/
|
||||
inline void add_float(uint32_t field_id_size, float value) {
|
||||
static inline void add_float_field(uint32_t &total_size, uint32_t field_id_size, float value) {
|
||||
if (value != 0.0f) {
|
||||
total_size_ += field_id_size + 4;
|
||||
total_size += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,9 +583,9 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of a fixed32 field to the total message size
|
||||
*/
|
||||
inline void add_fixed32(uint32_t field_id_size, uint32_t value) {
|
||||
static inline void add_fixed32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
if (value != 0) {
|
||||
total_size_ += field_id_size + 4;
|
||||
total_size += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,104 +595,149 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sfixed32 field to the total message size
|
||||
*/
|
||||
inline void add_sfixed32(uint32_t field_id_size, int32_t value) {
|
||||
static inline void add_sfixed32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
total_size_ += field_id_size + 4;
|
||||
total_size += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: add_sfixed64_field removed - wire type 1 (64-bit: sfixed64) not supported
|
||||
// to reduce overhead on embedded systems
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an enum field to the total message size
|
||||
*
|
||||
* Enum fields are encoded as uint32 varints.
|
||||
*/
|
||||
static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Enums are encoded as uint32
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an enum field to the total message size (repeated field version)
|
||||
*
|
||||
* Enum fields are encoded as uint32 varints.
|
||||
*/
|
||||
static inline void add_enum_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
// Enums are encoded as uint32
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size
|
||||
*
|
||||
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
||||
*/
|
||||
inline void add_sint32(uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
add_sint32_force(field_id_size, value);
|
||||
static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
||||
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
||||
total_size += field_id_size + varint(zigzag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size (repeated field version)
|
||||
*
|
||||
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
||||
*/
|
||||
inline void add_sint32_force(uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size when force is true
|
||||
static inline void add_sint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
||||
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
||||
total_size_ += field_id_size + varint(zigzag);
|
||||
total_size += field_id_size + varint(zigzag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size
|
||||
*/
|
||||
inline void add_int64(uint32_t field_id_size, int64_t value) {
|
||||
if (value != 0) {
|
||||
add_int64_force(field_id_size, value);
|
||||
static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_int64_force(uint32_t field_id_size, int64_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
static inline void add_int64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size
|
||||
*/
|
||||
inline void add_uint64(uint32_t field_id_size, uint64_t value) {
|
||||
if (value != 0) {
|
||||
add_uint64_force(field_id_size, value);
|
||||
static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_uint64_force(uint32_t field_id_size, uint64_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
static inline void add_uint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
// NOTE: sint64 support functions (add_sint64_field, add_sint64_field_force) removed
|
||||
// NOTE: sint64 support functions (add_sint64_field, add_sint64_field_repeated) removed
|
||||
// sint64 type is not supported by ESPHome API to reduce overhead on embedded systems
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size
|
||||
* @brief Calculates and adds the size of a string field using length
|
||||
*/
|
||||
inline void add_length(uint32_t field_id_size, size_t len) {
|
||||
if (len != 0) {
|
||||
add_length_force(field_id_size, len);
|
||||
static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, size_t len) {
|
||||
// Skip calculation if string is empty
|
||||
if (len == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Field ID + length varint + string bytes
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size (repeated
|
||||
* field version)
|
||||
* @brief Calculates and adds the size of a string/bytes field to the total message size (repeated field version)
|
||||
*/
|
||||
inline void add_length_force(uint32_t field_id_size, size_t len) {
|
||||
// Always calculate size when force is true
|
||||
static inline void add_string_field_repeated(uint32_t &total_size, uint32_t field_id_size, const std::string &str) {
|
||||
// Always calculate size for repeated fields
|
||||
const uint32_t str_size = static_cast<uint32_t>(str.size());
|
||||
total_size += field_id_size + varint(str_size) + str_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a bytes field to the total message size
|
||||
*/
|
||||
static inline void add_bytes_field(uint32_t &total_size, uint32_t field_id_size, size_t len) {
|
||||
// Skip calculation if bytes is empty
|
||||
if (len == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Field ID + length varint + data bytes
|
||||
total_size_ += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a pre-calculated size directly to the total
|
||||
*
|
||||
* This is used when we can calculate the total size by multiplying the number
|
||||
* of elements by the bytes per element (for repeated fixed-size types like float, fixed32, etc.)
|
||||
*
|
||||
* @param size The pre-calculated total size to add
|
||||
*/
|
||||
inline void add_precalculated_size(uint32_t size) { total_size_ += size; }
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size
|
||||
*
|
||||
@@ -686,21 +746,26 @@ class ProtoSize {
|
||||
*
|
||||
* @param nested_size The pre-calculated size of the nested message
|
||||
*/
|
||||
inline void add_message_field(uint32_t field_id_size, uint32_t nested_size) {
|
||||
if (nested_size != 0) {
|
||||
add_message_field_force(field_id_size, nested_size);
|
||||
static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Skip calculation if nested message is empty
|
||||
if (nested_size == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
// Field ID + length varint + nested message content
|
||||
total_size += field_id_size + varint(nested_size) + nested_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
||||
*
|
||||
* @param nested_size The pre-calculated size of the nested message
|
||||
*/
|
||||
inline void add_message_field_force(uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Always calculate size when force is true
|
||||
static inline void add_message_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Always calculate size for repeated fields
|
||||
// Field ID + length varint + nested message content
|
||||
total_size_ += field_id_size + varint(nested_size) + nested_size;
|
||||
total_size += field_id_size + varint(nested_size) + nested_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -712,29 +777,26 @@ class ProtoSize {
|
||||
*
|
||||
* @param message The nested message object
|
||||
*/
|
||||
inline void add_message_object(uint32_t field_id_size, const ProtoMessage &message) {
|
||||
// Calculate nested message size by creating a temporary ProtoSize
|
||||
ProtoSize nested_calc;
|
||||
message.calculate_size(nested_calc);
|
||||
uint32_t nested_size = nested_calc.get_size();
|
||||
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message) {
|
||||
uint32_t nested_size = 0;
|
||||
message.calculate_size(nested_size);
|
||||
|
||||
// Use the base implementation with the calculated nested_size
|
||||
add_message_field(field_id_size, nested_size);
|
||||
add_message_field(total_size, field_id_size, nested_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (force version)
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
||||
*
|
||||
* @param message The nested message object
|
||||
*/
|
||||
inline void add_message_object_force(uint32_t field_id_size, const ProtoMessage &message) {
|
||||
// Calculate nested message size by creating a temporary ProtoSize
|
||||
ProtoSize nested_calc;
|
||||
message.calculate_size(nested_calc);
|
||||
uint32_t nested_size = nested_calc.get_size();
|
||||
static inline void add_message_object_repeated(uint32_t &total_size, uint32_t field_id_size,
|
||||
const ProtoMessage &message) {
|
||||
uint32_t nested_size = 0;
|
||||
message.calculate_size(nested_size);
|
||||
|
||||
// Use the base implementation with the calculated nested_size
|
||||
add_message_field_force(field_id_size, nested_size);
|
||||
add_message_field_repeated(total_size, field_id_size, nested_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,15 +809,16 @@ class ProtoSize {
|
||||
* @param messages Vector of message objects
|
||||
*/
|
||||
template<typename MessageType>
|
||||
inline void add_repeated_message(uint32_t field_id_size, const std::vector<MessageType> &messages) {
|
||||
static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size,
|
||||
const std::vector<MessageType> &messages) {
|
||||
// Skip if the vector is empty
|
||||
if (messages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the force version for all messages in the repeated field
|
||||
// Use the repeated field version for all messages
|
||||
for (const auto &message : messages) {
|
||||
add_message_object_force(field_id_size, message);
|
||||
add_message_object_repeated(total_size, field_id_size, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -765,9 +828,8 @@ inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessa
|
||||
this->encode_field_raw(field_id, 2); // type 2: Length-delimited message
|
||||
|
||||
// Calculate the message size first
|
||||
ProtoSize msg_size;
|
||||
value.calculate_size(msg_size);
|
||||
uint32_t msg_length_bytes = msg_size.get_size();
|
||||
uint32_t msg_length_bytes = 0;
|
||||
value.calculate_size(msg_length_bytes);
|
||||
|
||||
// Calculate how many bytes the length varint needs
|
||||
uint32_t varint_length_bytes = ProtoSize::varint(msg_length_bytes);
|
||||
@@ -799,9 +861,7 @@ class ProtoService {
|
||||
virtual bool is_authenticated() = 0;
|
||||
virtual bool is_connection_setup() = 0;
|
||||
virtual void on_fatal_error() = 0;
|
||||
#ifdef USE_API_PASSWORD
|
||||
virtual void on_unauthenticated_access() = 0;
|
||||
#endif
|
||||
virtual void on_no_setup_connection() = 0;
|
||||
/**
|
||||
* Create a buffer with a reserved size.
|
||||
@@ -816,9 +876,8 @@ class ProtoService {
|
||||
|
||||
// Optimized method that pre-allocates buffer based on message size
|
||||
bool send_message_(const ProtoMessage &msg, uint8_t message_type) {
|
||||
ProtoSize size;
|
||||
msg.calculate_size(size);
|
||||
uint32_t msg_size = size.get_size();
|
||||
uint32_t msg_size = 0;
|
||||
msg.calculate_size(msg_size);
|
||||
|
||||
// Create a pre-sized buffer
|
||||
auto buffer = this->create_buffer(msg_size);
|
||||
@@ -840,7 +899,6 @@ class ProtoService {
|
||||
}
|
||||
|
||||
bool check_authenticated_() {
|
||||
#ifdef USE_API_PASSWORD
|
||||
if (!this->check_connection_setup_()) {
|
||||
return false;
|
||||
}
|
||||
@@ -849,10 +907,8 @@ class ProtoService {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return this->check_connection_setup_();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -3,7 +3,8 @@
|
||||
#include "api_connection.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Generate entity handler implementations using macros
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
@@ -68,5 +69,6 @@ INITIAL_STATE_HANDLER(update, update::UpdateEntity)
|
||||
|
||||
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -5,7 +5,8 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/component_iterator.h"
|
||||
#include "esphome/core/controller.h"
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIConnection;
|
||||
|
||||
@@ -88,5 +89,6 @@ class InitialStateIterator : public ComponentIterator {
|
||||
APIConnection *client_;
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -1,7 +1,8 @@
|
||||
#include "user_services.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
template<> bool get_execute_arg_value<bool>(const ExecuteServiceArgument &arg) { return arg.bool_; }
|
||||
template<> int32_t get_execute_arg_value<int32_t>(const ExecuteServiceArgument &arg) {
|
||||
@@ -39,4 +40,5 @@ template<> enums::ServiceArgType to_service_arg_type<std::vector<std::string>>()
|
||||
return enums::SERVICE_ARG_TYPE_STRING_ARRAY;
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
@@ -8,7 +8,8 @@
|
||||
#include "api_pb2.h"
|
||||
|
||||
#ifdef USE_API_SERVICES
|
||||
namespace esphome::api {
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class UserServiceDescriptor {
|
||||
public:
|
||||
@@ -73,5 +74,6 @@ template<typename... Ts> class UserServiceTrigger : public UserServiceBase<Ts...
|
||||
void execute(Ts... x) override { this->trigger(x...); } // NOLINT
|
||||
};
|
||||
|
||||
} // namespace esphome::api
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
#endif // USE_API_SERVICES
|
||||
|
@@ -7,6 +7,8 @@ namespace as3935 {
|
||||
static const char *const TAG = "as3935";
|
||||
|
||||
void AS3935Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
this->irq_pin_->setup();
|
||||
LOG_PIN(" IRQ Pin: ", this->irq_pin_);
|
||||
|
||||
|
@@ -7,7 +7,9 @@ namespace as3935_spi {
|
||||
static const char *const TAG = "as3935_spi";
|
||||
|
||||
void SPIAS3935Component::setup() {
|
||||
ESP_LOGI(TAG, "SPIAS3935Component setup started!");
|
||||
this->spi_setup();
|
||||
ESP_LOGI(TAG, "SPI setup finished!");
|
||||
AS3935Component::setup();
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,8 @@ static const uint8_t REGISTER_AGC = 0x1A; // 8 bytes / R
|
||||
static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R
|
||||
|
||||
void AS5600Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
if (!this->read_byte(REGISTER_STATUS).has_value()) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
|
@@ -8,6 +8,7 @@ namespace as7341 {
|
||||
static const char *const TAG = "as7341";
|
||||
|
||||
void AS7341Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
// Verify device ID
|
||||
|
@@ -10,7 +10,7 @@ from esphome.const import (
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
CODEOWNERS = ["@OttoWinter"]
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema({}),
|
||||
|
@@ -71,7 +71,7 @@ bool AT581XComponent::i2c_read_reg(uint8_t addr, uint8_t &data) {
|
||||
return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR;
|
||||
}
|
||||
|
||||
void AT581XComponent::setup() {}
|
||||
void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Running setup"); }
|
||||
void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); }
|
||||
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||
bool AT581XComponent::i2c_write_config() {
|
||||
|
@@ -41,6 +41,7 @@ void ATM90E26Component::update() {
|
||||
}
|
||||
|
||||
void ATM90E26Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->spi_setup();
|
||||
|
||||
uint16_t mmode = 0x422; // default values for everything but L/N line current gains
|
||||
|
@@ -109,6 +109,7 @@ void ATM90E32Component::update() {
|
||||
}
|
||||
|
||||
void ATM90E32Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->spi_setup();
|
||||
|
||||
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
||||
|
@@ -17,6 +17,7 @@ constexpr static const uint8_t AXS_READ_TOUCHPAD[11] = {0xb5, 0xab, 0xa5, 0x5a,
|
||||
}
|
||||
|
||||
void AXS15231Touchscreen::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup();
|
||||
this->reset_pin_->digital_write(false);
|
||||
@@ -35,6 +36,7 @@ void AXS15231Touchscreen::setup() {
|
||||
if (this->y_raw_max_ == 0) {
|
||||
this->y_raw_max_ = this->display_->get_native_height();
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen setup complete");
|
||||
}
|
||||
|
||||
void AXS15231Touchscreen::update_touches() {
|
||||
|
@@ -121,6 +121,8 @@ void spi_dma_tx_finish_callback(unsigned int param) {
|
||||
}
|
||||
|
||||
void BekenSPILEDStripLightOutput::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
size_t buffer_size = this->get_buffer_size_();
|
||||
size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
|
||||
|
||||
|
@@ -38,6 +38,7 @@ MTreg:
|
||||
*/
|
||||
|
||||
void BH1750Sensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->name_.c_str());
|
||||
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
|
||||
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
|
||||
this->mark_failed();
|
||||
|
@@ -266,10 +266,8 @@ async def delayed_off_filter_to_code(config, filter_id):
|
||||
async def autorepeat_filter_to_code(config, filter_id):
|
||||
timings = []
|
||||
if len(config) > 0:
|
||||
timings.extend(
|
||||
(conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON])
|
||||
for conf in config
|
||||
)
|
||||
for conf in config:
|
||||
timings.append((conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON]))
|
||||
else:
|
||||
timings.append(
|
||||
(
|
||||
@@ -516,7 +514,6 @@ def binary_sensor_schema(
|
||||
icon: str = cv.UNDEFINED,
|
||||
entity_category: str = cv.UNDEFINED,
|
||||
device_class: str = cv.UNDEFINED,
|
||||
filters: list = cv.UNDEFINED,
|
||||
) -> cv.Schema:
|
||||
schema = {}
|
||||
|
||||
@@ -528,7 +525,6 @@ def binary_sensor_schema(
|
||||
(CONF_ICON, icon, cv.icon),
|
||||
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
||||
(CONF_DEVICE_CLASS, device_class, validate_device_class),
|
||||
(CONF_FILTERS, filters, validate_filters),
|
||||
]:
|
||||
if default is not cv.UNDEFINED:
|
||||
schema[cv.Optional(key, default=default)] = validator
|
||||
@@ -577,15 +573,16 @@ async def setup_binary_sensor_core_(var, config):
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_MULTI_CLICK, []):
|
||||
timings = [
|
||||
cg.StructInitializer(
|
||||
MultiClickTriggerEvent,
|
||||
("state", tim[CONF_STATE]),
|
||||
("min_length", tim[CONF_MIN_LENGTH]),
|
||||
("max_length", tim.get(CONF_MAX_LENGTH, 4294967294)),
|
||||
timings = []
|
||||
for tim in conf[CONF_TIMING]:
|
||||
timings.append(
|
||||
cg.StructInitializer(
|
||||
MultiClickTriggerEvent,
|
||||
("state", tim[CONF_STATE]),
|
||||
("min_length", tim[CONF_MIN_LENGTH]),
|
||||
("max_length", tim.get(CONF_MAX_LENGTH, 4294967294)),
|
||||
)
|
||||
)
|
||||
for tim in conf[CONF_TIMING]
|
||||
]
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings)
|
||||
if CONF_INVALID_COOLDOWN in conf:
|
||||
cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
|
||||
@@ -654,6 +651,7 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args)
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_BINARY_SENSOR")
|
||||
cg.add_global(binary_sensor_ns.using)
|
||||
|
||||
|
||||
|
@@ -175,7 +175,8 @@ BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema(
|
||||
)
|
||||
async def ble_disconnect_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, parent)
|
||||
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -183,7 +184,8 @@ async def ble_disconnect_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def ble_connect_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, parent)
|
||||
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -280,7 +282,9 @@ async def passkey_reply_to_code(config, action_id, template_arg, args):
|
||||
)
|
||||
async def remove_bond_to_code(config, action_id, template_arg, args):
|
||||
parent = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, parent)
|
||||
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||
|
||||
return var
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
|
@@ -1,19 +1,13 @@
|
||||
import logging
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_ble, esp32_ble_client, esp32_ble_tracker
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||
from esphome.components.esp32_ble import BTLoggers
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ACTIVE, CONF_ID
|
||||
from esphome.core import CORE
|
||||
from esphome.log import AnsiFore, color
|
||||
|
||||
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
|
||||
DEPENDENCIES = ["api", "esp32"]
|
||||
CODEOWNERS = ["@jesserockz", "@bdraco"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
CONF_CONNECTION_SLOTS = "connection_slots"
|
||||
CONF_CACHE_SERVICES = "cache_services"
|
||||
@@ -47,27 +41,6 @@ def validate_connections(config):
|
||||
esp32_ble_tracker.consume_connection_slots(connection_slots, "bluetooth_proxy")(
|
||||
config
|
||||
)
|
||||
|
||||
# Warn about connection slot waste when using Arduino framework
|
||||
if CORE.using_arduino and connection_slots:
|
||||
_LOGGER.warning(
|
||||
"Bluetooth Proxy with active connections on Arduino framework has suboptimal performance.\n"
|
||||
"If BLE connections fail, they can waste connection slots for 10 seconds because\n"
|
||||
"Arduino doesn't allow configuring the BLE connection timeout (fixed at 30s).\n"
|
||||
"ESP-IDF framework allows setting it to 20s to match client timeouts.\n"
|
||||
"\n"
|
||||
"To switch to ESP-IDF, add this to your YAML:\n"
|
||||
" esp32:\n"
|
||||
" framework:\n"
|
||||
" type: esp-idf\n"
|
||||
"\n"
|
||||
"For detailed migration instructions, see:\n"
|
||||
"%s",
|
||||
color(
|
||||
AnsiFore.BLUE, "https://esphome.io/guides/esp32_arduino_to_idf.html"
|
||||
),
|
||||
)
|
||||
|
||||
return {
|
||||
**config,
|
||||
CONF_CONNECTIONS: [CONNECTION_SCHEMA({}) for _ in range(connection_slots)],
|
||||
@@ -114,10 +87,6 @@ async def to_code(config):
|
||||
cg.add(var.set_active(config[CONF_ACTIVE]))
|
||||
await esp32_ble_tracker.register_raw_ble_device(var, config)
|
||||
|
||||
# Define max connections for protobuf fixed array
|
||||
connection_count = len(config.get(CONF_CONNECTIONS, []))
|
||||
cg.add_define("BLUETOOTH_PROXY_MAX_CONNECTIONS", connection_count)
|
||||
|
||||
for connection_conf in config.get(CONF_CONNECTIONS, []):
|
||||
connection_var = cg.new_Pvariable(connection_conf[CONF_ID])
|
||||
await cg.register_component(connection_var, connection_conf)
|
||||
|
@@ -24,107 +24,21 @@ static void fill_128bit_uuid_array(std::array<uint64_t, 2> &out, esp_bt_uuid_t u
|
||||
((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0]);
|
||||
}
|
||||
|
||||
// Helper to fill UUID in the appropriate format based on client support and UUID type
|
||||
static void fill_gatt_uuid(std::array<uint64_t, 2> &uuid_128, uint32_t &short_uuid, const esp_bt_uuid_t &uuid,
|
||||
bool use_efficient_uuids) {
|
||||
if (!use_efficient_uuids || uuid.len == ESP_UUID_LEN_128) {
|
||||
// Use 128-bit format for old clients or when UUID is already 128-bit
|
||||
fill_128bit_uuid_array(uuid_128, uuid);
|
||||
} else if (uuid.len == ESP_UUID_LEN_16) {
|
||||
short_uuid = uuid.uuid.uuid16;
|
||||
} else if (uuid.len == ESP_UUID_LEN_32) {
|
||||
short_uuid = uuid.uuid.uuid32;
|
||||
}
|
||||
}
|
||||
|
||||
// Constants for size estimation
|
||||
static constexpr uint8_t SERVICE_OVERHEAD_LEGACY = 25; // UUID(20) + handle(4) + overhead(1)
|
||||
static constexpr uint8_t SERVICE_OVERHEAD_EFFICIENT = 10; // UUID(6) + handle(4)
|
||||
static constexpr uint8_t CHAR_SIZE_128BIT = 35; // UUID(20) + handle(4) + props(4) + overhead(7)
|
||||
static constexpr uint8_t DESC_SIZE_128BIT = 25; // UUID(20) + handle(4) + overhead(1)
|
||||
static constexpr uint8_t DESC_SIZE_16BIT = 10; // UUID(6) + handle(4)
|
||||
static constexpr uint8_t DESC_PER_CHAR = 1; // Assume 1 descriptor per characteristic
|
||||
|
||||
// Helper to estimate service size before fetching all data
|
||||
/**
|
||||
* Estimate the size of a Bluetooth service based on the number of characteristics and UUID format.
|
||||
*
|
||||
* @param char_count The number of characteristics in the service.
|
||||
* @param use_efficient_uuids Whether to use efficient UUIDs (16-bit or 32-bit) for newer APIVersions.
|
||||
* @return The estimated size of the service in bytes.
|
||||
*
|
||||
* This function calculates the size of a Bluetooth service by considering:
|
||||
* - A service overhead, which depends on whether efficient UUIDs are used.
|
||||
* - The size of each characteristic, assuming 128-bit UUIDs for safety.
|
||||
* - The size of descriptors, assuming one 128-bit descriptor per characteristic.
|
||||
*/
|
||||
static size_t estimate_service_size(uint16_t char_count, bool use_efficient_uuids) {
|
||||
size_t service_overhead = use_efficient_uuids ? SERVICE_OVERHEAD_EFFICIENT : SERVICE_OVERHEAD_LEGACY;
|
||||
// Always assume 128-bit UUIDs for characteristics to be safe
|
||||
size_t char_size = CHAR_SIZE_128BIT;
|
||||
// Assume one 128-bit descriptor per characteristic
|
||||
size_t desc_size = DESC_SIZE_128BIT * DESC_PER_CHAR;
|
||||
|
||||
return service_overhead + (char_size + desc_size) * char_count;
|
||||
}
|
||||
|
||||
bool BluetoothConnection::supports_efficient_uuids_() const {
|
||||
auto *api_conn = this->proxy_->get_api_connection();
|
||||
return api_conn && api_conn->client_supports_api_version(1, 12);
|
||||
}
|
||||
|
||||
void BluetoothConnection::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "BLE Connection:");
|
||||
BLEClientBase::dump_config();
|
||||
}
|
||||
|
||||
void BluetoothConnection::update_allocated_slot_(uint64_t find_value, uint64_t set_value) {
|
||||
auto &allocated = this->proxy_->connections_free_response_.allocated;
|
||||
for (auto &slot : allocated) {
|
||||
if (slot == find_value) {
|
||||
slot = set_value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothConnection::set_address(uint64_t address) {
|
||||
// If we're clearing an address (disconnecting), update the pre-allocated message
|
||||
if (address == 0 && this->address_ != 0) {
|
||||
this->proxy_->connections_free_response_.free++;
|
||||
this->update_allocated_slot_(this->address_, 0);
|
||||
}
|
||||
// If we're setting a new address (connecting), update the pre-allocated message
|
||||
else if (address != 0 && this->address_ == 0) {
|
||||
this->proxy_->connections_free_response_.free--;
|
||||
this->update_allocated_slot_(0, address);
|
||||
}
|
||||
|
||||
// Call parent implementation to actually set the address
|
||||
BLEClientBase::set_address(address);
|
||||
}
|
||||
|
||||
void BluetoothConnection::loop() {
|
||||
BLEClientBase::loop();
|
||||
|
||||
// Early return if no active connection
|
||||
if (this->address_ == 0) {
|
||||
// Early return if no active connection or not in service discovery phase
|
||||
if (this->address_ == 0 || this->send_service_ < 0 || this->send_service_ > this->service_count_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle service discovery if in valid range
|
||||
if (this->send_service_ >= 0 && this->send_service_ <= this->service_count_) {
|
||||
this->send_service_for_discovery_();
|
||||
}
|
||||
|
||||
// Check if we should disable the loop
|
||||
// - For V3_WITH_CACHE: Services are never sent, disable after INIT state
|
||||
// - For other connections: Disable only after service discovery is complete
|
||||
// (send_service_ == DONE_SENDING_SERVICES, which is only set after services are sent)
|
||||
if (this->state_ != espbt::ClientState::INIT && (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||
this->send_service_ == DONE_SENDING_SERVICES)) {
|
||||
this->disable_loop();
|
||||
}
|
||||
// Handle service discovery
|
||||
this->send_service_for_discovery_();
|
||||
}
|
||||
|
||||
void BluetoothConnection::reset_connection_(esp_err_t reason) {
|
||||
@@ -138,12 +52,12 @@ void BluetoothConnection::reset_connection_(esp_err_t reason) {
|
||||
// to detect incomplete service discovery rather than relying on us to
|
||||
// tell them about a partial list.
|
||||
this->set_address(0);
|
||||
this->send_service_ = INIT_SENDING_SERVICES;
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
this->proxy_->send_connections_free();
|
||||
}
|
||||
|
||||
void BluetoothConnection::send_service_for_discovery_() {
|
||||
if (this->send_service_ >= this->service_count_) {
|
||||
if (this->send_service_ == this->service_count_) {
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
this->proxy_->send_gatt_services_done(this->address_);
|
||||
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||
@@ -156,207 +70,120 @@ void BluetoothConnection::send_service_for_discovery_() {
|
||||
// Early return if no API connection
|
||||
auto *api_conn = this->proxy_->get_api_connection();
|
||||
if (api_conn == nullptr) {
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if client supports efficient UUIDs
|
||||
bool use_efficient_uuids = this->supports_efficient_uuids_();
|
||||
// Send next service
|
||||
esp_gattc_service_elem_t service_result;
|
||||
uint16_t service_count = 1;
|
||||
esp_gatt_status_t service_status = esp_ble_gattc_get_service(this->gattc_if_, this->conn_id_, nullptr,
|
||||
&service_result, &service_count, this->send_service_);
|
||||
this->send_service_++;
|
||||
|
||||
if (service_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d", this->connection_index_,
|
||||
this->address_str().c_str(), this->send_service_ - 1, service_status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (service_count == 0) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d", this->connection_index_,
|
||||
this->address_str().c_str(), service_count);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare response
|
||||
api::BluetoothGATTGetServicesResponse resp;
|
||||
resp.address = this->address_;
|
||||
auto &service_resp = resp.services[0];
|
||||
fill_128bit_uuid_array(service_resp.uuid, service_result.uuid);
|
||||
service_resp.handle = service_result.start_handle;
|
||||
|
||||
// Dynamic batching based on actual size
|
||||
// Conservative MTU limit for API messages (accounts for WPA3 overhead)
|
||||
static constexpr size_t MAX_PACKET_SIZE = 1360;
|
||||
// Get the number of characteristics directly with one call
|
||||
uint16_t total_char_count = 0;
|
||||
esp_gatt_status_t char_count_status =
|
||||
esp_ble_gattc_get_attr_count(this->gattc_if_, this->conn_id_, ESP_GATT_DB_CHARACTERISTIC,
|
||||
service_result.start_handle, service_result.end_handle, 0, &total_char_count);
|
||||
|
||||
// Keep running total of actual message size
|
||||
size_t current_size = 0;
|
||||
api::ProtoSize size;
|
||||
resp.calculate_size(size);
|
||||
current_size = size.get_size();
|
||||
|
||||
while (this->send_service_ < this->service_count_) {
|
||||
esp_gattc_service_elem_t service_result;
|
||||
uint16_t service_count = 1;
|
||||
esp_gatt_status_t service_status = esp_ble_gattc_get_service(this->gattc_if_, this->conn_id_, nullptr,
|
||||
&service_result, &service_count, this->send_service_);
|
||||
|
||||
if (service_status != ESP_GATT_OK || service_count == 0) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service %s, status=%d, service_count=%d, offset=%d",
|
||||
this->connection_index_, this->address_str().c_str(),
|
||||
service_status != ESP_GATT_OK ? "error" : "missing", service_status, service_count, this->send_service_);
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the number of characteristics BEFORE adding to response
|
||||
uint16_t total_char_count = 0;
|
||||
esp_gatt_status_t char_count_status =
|
||||
esp_ble_gattc_get_attr_count(this->gattc_if_, this->conn_id_, ESP_GATT_DB_CHARACTERISTIC,
|
||||
service_result.start_handle, service_result.end_handle, 0, &total_char_count);
|
||||
|
||||
if (char_count_status != ESP_GATT_OK) {
|
||||
this->log_connection_error_("esp_ble_gattc_get_attr_count", char_count_status);
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this service likely won't fit, send current batch (unless it's the first)
|
||||
size_t estimated_size = estimate_service_size(total_char_count, use_efficient_uuids);
|
||||
if (!resp.services.empty() && (current_size + estimated_size > MAX_PACKET_SIZE)) {
|
||||
// This service likely won't fit, send current batch
|
||||
break;
|
||||
}
|
||||
|
||||
// Now add the service since we know it will likely fit
|
||||
resp.services.emplace_back();
|
||||
auto &service_resp = resp.services.back();
|
||||
|
||||
fill_gatt_uuid(service_resp.uuid, service_resp.short_uuid, service_result.uuid, use_efficient_uuids);
|
||||
|
||||
service_resp.handle = service_result.start_handle;
|
||||
|
||||
if (total_char_count > 0) {
|
||||
// Reserve space and process characteristics
|
||||
service_resp.characteristics.reserve(total_char_count);
|
||||
uint16_t char_offset = 0;
|
||||
esp_gattc_char_elem_t char_result;
|
||||
while (true) { // characteristics
|
||||
uint16_t char_count = 1;
|
||||
esp_gatt_status_t char_status =
|
||||
esp_ble_gattc_get_all_char(this->gattc_if_, this->conn_id_, service_result.start_handle,
|
||||
service_result.end_handle, &char_result, &char_count, char_offset);
|
||||
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (char_status != ESP_GATT_OK) {
|
||||
this->log_connection_error_("esp_ble_gattc_get_all_char", char_status);
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
if (char_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
service_resp.characteristics.emplace_back();
|
||||
auto &characteristic_resp = service_resp.characteristics.back();
|
||||
|
||||
fill_gatt_uuid(characteristic_resp.uuid, characteristic_resp.short_uuid, char_result.uuid, use_efficient_uuids);
|
||||
|
||||
characteristic_resp.handle = char_result.char_handle;
|
||||
characteristic_resp.properties = char_result.properties;
|
||||
char_offset++;
|
||||
|
||||
// Get the number of descriptors directly with one call
|
||||
uint16_t total_desc_count = 0;
|
||||
esp_gatt_status_t desc_count_status = esp_ble_gattc_get_attr_count(
|
||||
this->gattc_if_, this->conn_id_, ESP_GATT_DB_DESCRIPTOR, 0, 0, char_result.char_handle, &total_desc_count);
|
||||
|
||||
if (desc_count_status != ESP_GATT_OK) {
|
||||
this->log_connection_error_("esp_ble_gattc_get_attr_count", desc_count_status);
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
if (total_desc_count == 0) {
|
||||
// No descriptors, continue to next characteristic
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reserve space and process descriptors
|
||||
characteristic_resp.descriptors.reserve(total_desc_count);
|
||||
uint16_t desc_offset = 0;
|
||||
esp_gattc_descr_elem_t desc_result;
|
||||
while (true) { // descriptors
|
||||
uint16_t desc_count = 1;
|
||||
esp_gatt_status_t desc_status = esp_ble_gattc_get_all_descr(
|
||||
this->gattc_if_, this->conn_id_, char_result.char_handle, &desc_result, &desc_count, desc_offset);
|
||||
if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (desc_status != ESP_GATT_OK) {
|
||||
this->log_connection_error_("esp_ble_gattc_get_all_descr", desc_status);
|
||||
this->send_service_ = DONE_SENDING_SERVICES;
|
||||
return;
|
||||
}
|
||||
if (desc_count == 0) {
|
||||
break; // No more descriptors
|
||||
}
|
||||
|
||||
characteristic_resp.descriptors.emplace_back();
|
||||
auto &descriptor_resp = characteristic_resp.descriptors.back();
|
||||
|
||||
fill_gatt_uuid(descriptor_resp.uuid, descriptor_resp.short_uuid, desc_result.uuid, use_efficient_uuids);
|
||||
|
||||
descriptor_resp.handle = desc_result.handle;
|
||||
desc_offset++;
|
||||
}
|
||||
}
|
||||
} // end if (total_char_count > 0)
|
||||
|
||||
// Calculate the actual size of just this service
|
||||
api::ProtoSize service_sizer;
|
||||
service_resp.calculate_size(service_sizer);
|
||||
size_t service_size = service_sizer.get_size() + 1; // +1 for field tag
|
||||
|
||||
// Check if adding this service would exceed the limit
|
||||
if (current_size + service_size > MAX_PACKET_SIZE) {
|
||||
// We would go over - pop the last service if we have more than one
|
||||
if (resp.services.size() > 1) {
|
||||
resp.services.pop_back();
|
||||
ESP_LOGD(TAG, "[%d] [%s] Service %d would exceed limit (current: %d + service: %d > %d), sending current batch",
|
||||
this->connection_index_, this->address_str().c_str(), this->send_service_, current_size, service_size,
|
||||
MAX_PACKET_SIZE);
|
||||
// Don't increment send_service_ - we'll retry this service in next batch
|
||||
} else {
|
||||
// This single service is too large, but we have to send it anyway
|
||||
ESP_LOGV(TAG, "[%d] [%s] Service %d is too large (%d bytes) but sending anyway", this->connection_index_,
|
||||
this->address_str().c_str(), this->send_service_, service_size);
|
||||
// Increment so we don't get stuck
|
||||
this->send_service_++;
|
||||
}
|
||||
// Send what we have
|
||||
break;
|
||||
}
|
||||
|
||||
// Now we know we're keeping this service, add its size
|
||||
current_size += service_size;
|
||||
// Successfully added this service, increment counter
|
||||
this->send_service_++;
|
||||
if (char_count_status == ESP_GATT_OK && total_char_count > 0) {
|
||||
// Only reserve if we successfully got a count
|
||||
service_resp.characteristics.reserve(total_char_count);
|
||||
} else if (char_count_status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error getting characteristic count, status=%d", this->connection_index_,
|
||||
this->address_str().c_str(), char_count_status);
|
||||
}
|
||||
|
||||
// Send the message with dynamically batched services
|
||||
// Now process characteristics
|
||||
uint16_t char_offset = 0;
|
||||
esp_gattc_char_elem_t char_result;
|
||||
while (true) { // characteristics
|
||||
uint16_t char_count = 1;
|
||||
esp_gatt_status_t char_status =
|
||||
esp_ble_gattc_get_all_char(this->gattc_if_, this->conn_id_, service_result.start_handle,
|
||||
service_result.end_handle, &char_result, &char_count, char_offset);
|
||||
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (char_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", this->connection_index_,
|
||||
this->address_str().c_str(), char_status);
|
||||
break;
|
||||
}
|
||||
if (char_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
service_resp.characteristics.emplace_back();
|
||||
auto &characteristic_resp = service_resp.characteristics.back();
|
||||
fill_128bit_uuid_array(characteristic_resp.uuid, char_result.uuid);
|
||||
characteristic_resp.handle = char_result.char_handle;
|
||||
characteristic_resp.properties = char_result.properties;
|
||||
char_offset++;
|
||||
|
||||
// Get the number of descriptors directly with one call
|
||||
uint16_t total_desc_count = 0;
|
||||
esp_gatt_status_t desc_count_status =
|
||||
esp_ble_gattc_get_attr_count(this->gattc_if_, this->conn_id_, ESP_GATT_DB_DESCRIPTOR, char_result.char_handle,
|
||||
service_result.end_handle, 0, &total_desc_count);
|
||||
|
||||
if (desc_count_status == ESP_GATT_OK && total_desc_count > 0) {
|
||||
// Only reserve if we successfully got a count
|
||||
characteristic_resp.descriptors.reserve(total_desc_count);
|
||||
} else if (desc_count_status != ESP_GATT_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error getting descriptor count for char handle %d, status=%d", this->connection_index_,
|
||||
this->address_str().c_str(), char_result.char_handle, desc_count_status);
|
||||
}
|
||||
|
||||
// Now process descriptors
|
||||
uint16_t desc_offset = 0;
|
||||
esp_gattc_descr_elem_t desc_result;
|
||||
while (true) { // descriptors
|
||||
uint16_t desc_count = 1;
|
||||
esp_gatt_status_t desc_status = esp_ble_gattc_get_all_descr(
|
||||
this->gattc_if_, this->conn_id_, char_result.char_handle, &desc_result, &desc_count, desc_offset);
|
||||
if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (desc_status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", this->connection_index_,
|
||||
this->address_str().c_str(), desc_status);
|
||||
break;
|
||||
}
|
||||
if (desc_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
characteristic_resp.descriptors.emplace_back();
|
||||
auto &descriptor_resp = characteristic_resp.descriptors.back();
|
||||
fill_128bit_uuid_array(descriptor_resp.uuid, desc_result.uuid);
|
||||
descriptor_resp.handle = desc_result.handle;
|
||||
desc_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the message (we already checked api_conn is not null at the beginning)
|
||||
api_conn->send_message(resp, api::BluetoothGATTGetServicesResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
void BluetoothConnection::log_connection_error_(const char *operation, esp_gatt_status_t status) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] %s error, status=%d", this->connection_index_, this->address_str().c_str(), operation,
|
||||
status);
|
||||
}
|
||||
|
||||
void BluetoothConnection::log_connection_warning_(const char *operation, esp_err_t err) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] %s failed, err=%d", this->connection_index_, this->address_str().c_str(), operation, err);
|
||||
}
|
||||
|
||||
void BluetoothConnection::log_gatt_not_connected_(const char *action, const char *type) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot %s GATT %s, not connected.", this->connection_index_, this->address_str().c_str(),
|
||||
action, type);
|
||||
}
|
||||
|
||||
void BluetoothConnection::log_gatt_operation_error_(const char *operation, uint16_t handle, esp_gatt_status_t status) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error %s for handle 0x%2X, status=%d", this->connection_index_, this->address_str().c_str(),
|
||||
operation, handle, status);
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::check_and_log_error_(const char *operation, esp_err_t err) {
|
||||
if (err != ESP_OK) {
|
||||
this->log_connection_warning_(operation, err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t *param) {
|
||||
if (!BLEClientBase::gattc_event_handler(event, gattc_if, param))
|
||||
@@ -397,7 +224,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
||||
case ESP_GATTC_READ_DESCR_EVT:
|
||||
case ESP_GATTC_READ_CHAR_EVT: {
|
||||
if (param->read.status != ESP_GATT_OK) {
|
||||
this->log_gatt_operation_error_("reading char/descriptor", param->read.handle, param->read.status);
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error reading char/descriptor at handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->read.handle, param->read.status);
|
||||
this->proxy_->send_gatt_error(this->address_, param->read.handle, param->read.status);
|
||||
break;
|
||||
}
|
||||
@@ -411,7 +239,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
||||
case ESP_GATTC_WRITE_CHAR_EVT:
|
||||
case ESP_GATTC_WRITE_DESCR_EVT: {
|
||||
if (param->write.status != ESP_GATT_OK) {
|
||||
this->log_gatt_operation_error_("writing char/descriptor", param->write.handle, param->write.status);
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error writing char/descriptor at handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->write.handle, param->write.status);
|
||||
this->proxy_->send_gatt_error(this->address_, param->write.handle, param->write.status);
|
||||
break;
|
||||
}
|
||||
@@ -423,8 +252,9 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
||||
}
|
||||
case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
|
||||
if (param->unreg_for_notify.status != ESP_GATT_OK) {
|
||||
this->log_gatt_operation_error_("unregistering notifications", param->unreg_for_notify.handle,
|
||||
param->unreg_for_notify.status);
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d",
|
||||
this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle,
|
||||
param->unreg_for_notify.status);
|
||||
this->proxy_->send_gatt_error(this->address_, param->unreg_for_notify.handle, param->unreg_for_notify.status);
|
||||
break;
|
||||
}
|
||||
@@ -436,8 +266,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
||||
}
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
if (param->reg_for_notify.status != ESP_GATT_OK) {
|
||||
this->log_gatt_operation_error_("registering notifications", param->reg_for_notify.handle,
|
||||
param->reg_for_notify.status);
|
||||
ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status);
|
||||
this->proxy_->send_gatt_error(this->address_, param->reg_for_notify.handle, param->reg_for_notify.status);
|
||||
break;
|
||||
}
|
||||
@@ -483,7 +313,8 @@ void BluetoothConnection::gap_event_handler(esp_gap_ble_cb_event_t event, esp_bl
|
||||
|
||||
esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
|
||||
if (!this->connected()) {
|
||||
this->log_gatt_not_connected_("read", "characteristic");
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
@@ -491,12 +322,18 @@ esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
|
||||
handle);
|
||||
|
||||
esp_err_t err = esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
return this->check_and_log_error_("esp_ble_gattc_read_char", err);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::string &data, bool response) {
|
||||
if (!this->connected()) {
|
||||
this->log_gatt_not_connected_("write", "characteristic");
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
@@ -505,24 +342,36 @@ esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::
|
||||
esp_err_t err =
|
||||
esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
return this->check_and_log_error_("esp_ble_gattc_write_char", err);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
|
||||
if (!this->connected()) {
|
||||
this->log_gatt_not_connected_("read", "descriptor");
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT descriptor, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
handle);
|
||||
|
||||
esp_err_t err = esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
|
||||
return this->check_and_log_error_("esp_ble_gattc_read_char_descr", err);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data, bool response) {
|
||||
if (!this->connected()) {
|
||||
this->log_gatt_not_connected_("write", "descriptor");
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||
@@ -531,12 +380,18 @@ esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::stri
|
||||
esp_err_t err = esp_ble_gattc_write_char_descr(
|
||||
this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
return this->check_and_log_error_("esp_ble_gattc_write_char_descr", err);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enable) {
|
||||
if (!this->connected()) {
|
||||
this->log_gatt_not_connected_("notify", "characteristic");
|
||||
ESP_LOGW(TAG, "[%d] [%s] Cannot notify GATT characteristic, not connected.", this->connection_index_,
|
||||
this->address_str_.c_str());
|
||||
return ESP_GATT_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
@@ -544,13 +399,22 @@ esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enabl
|
||||
ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications handle %d", this->connection_index_,
|
||||
this->address_str_.c_str(), handle);
|
||||
esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, handle);
|
||||
return this->check_and_log_error_("esp_ble_gattc_register_for_notify", err);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications handle %d", this->connection_index_,
|
||||
this->address_str_.c_str(), handle);
|
||||
esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_,
|
||||
this->address_str_.c_str(), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications handle %d", this->connection_index_,
|
||||
this->address_str_.c_str(), handle);
|
||||
esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, handle);
|
||||
return this->check_and_log_error_("esp_ble_gattc_unregister_for_notify", err);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp32_ble_tracker::AdvertisementParserType BluetoothConnection::get_advertisement_parser_type() {
|
||||
|
@@ -24,27 +24,18 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
|
||||
|
||||
esp_err_t notify_characteristic(uint16_t handle, bool enable);
|
||||
|
||||
void set_address(uint64_t address) override;
|
||||
|
||||
protected:
|
||||
friend class BluetoothProxy;
|
||||
|
||||
bool supports_efficient_uuids_() const;
|
||||
void send_service_for_discovery_();
|
||||
void reset_connection_(esp_err_t reason);
|
||||
void update_allocated_slot_(uint64_t find_value, uint64_t set_value);
|
||||
void log_connection_error_(const char *operation, esp_gatt_status_t status);
|
||||
void log_connection_warning_(const char *operation, esp_err_t err);
|
||||
void log_gatt_not_connected_(const char *action, const char *type);
|
||||
void log_gatt_operation_error_(const char *operation, uint16_t handle, esp_gatt_status_t status);
|
||||
esp_err_t check_and_log_error_(const char *operation, esp_err_t err);
|
||||
|
||||
// Memory optimized layout for 32-bit systems
|
||||
// Group 1: Pointers (4 bytes each, naturally aligned)
|
||||
BluetoothProxy *proxy_;
|
||||
|
||||
// Group 2: 2-byte types
|
||||
int16_t send_service_{-3}; // -3 = INIT_SENDING_SERVICES, -2 = DONE_SENDING_SERVICES, >=0 = service index
|
||||
int16_t send_service_{-2}; // Needs to handle negative values and service count
|
||||
|
||||
// Group 3: 1-byte types
|
||||
bool seen_mtu_or_services_{false};
|
||||
|
@@ -25,16 +25,16 @@ static_assert(sizeof(((api::BluetoothLERawAdvertisement *) nullptr)->data) == 62
|
||||
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
||||
|
||||
void BluetoothProxy::setup() {
|
||||
// Pre-allocate response object
|
||||
this->response_ = std::make_unique<api::BluetoothLERawAdvertisementsResponse>();
|
||||
|
||||
// Reserve capacity but start with size 0
|
||||
// Reserve 50% since we'll grow naturally and flush at FLUSH_BATCH_SIZE
|
||||
this->response_.advertisements.reserve(FLUSH_BATCH_SIZE / 2);
|
||||
this->response_->advertisements.reserve(FLUSH_BATCH_SIZE / 2);
|
||||
|
||||
// Don't pre-allocate pool - let it grow only if needed in busy environments
|
||||
// Many devices in quiet areas will never need the overflow pool
|
||||
|
||||
this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
|
||||
this->parent_->add_scanner_state_callback([this](esp32_ble_tracker::ScannerState state) {
|
||||
if (this->api_connection_ != nullptr) {
|
||||
this->send_bluetooth_scanner_state_(state);
|
||||
@@ -50,26 +50,6 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta
|
||||
this->api_connection_->send_message(resp, api::BluetoothScannerStateResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
void BluetoothProxy::log_connection_request_ignored_(BluetoothConnection *connection, espbt::ClientState state) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, state: %s", connection->get_connection_index(),
|
||||
connection->address_str().c_str(), espbt::client_state_to_string(state));
|
||||
}
|
||||
|
||||
void BluetoothProxy::log_connection_info_(BluetoothConnection *connection, const char *message) {
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting %s", connection->get_connection_index(), connection->address_str().c_str(),
|
||||
message);
|
||||
}
|
||||
|
||||
void BluetoothProxy::log_not_connected_gatt_(const char *action, const char *type) {
|
||||
ESP_LOGW(TAG, "Cannot %s GATT %s, not connected", action, type);
|
||||
}
|
||||
|
||||
void BluetoothProxy::handle_gatt_not_connected_(uint64_t address, uint16_t handle, const char *action,
|
||||
const char *type) {
|
||||
this->log_not_connected_gatt_(action, type);
|
||||
this->send_gatt_error(address, handle, ESP_GATT_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32_BLE_DEVICE
|
||||
bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
|
||||
// This method should never be called since bluetooth_proxy always uses raw advertisements
|
||||
@@ -82,7 +62,7 @@ bool BluetoothProxy::parse_devices(const esp32_ble::BLEScanResult *scan_results,
|
||||
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr)
|
||||
return false;
|
||||
|
||||
auto &advertisements = this->response_.advertisements;
|
||||
auto &advertisements = this->response_->advertisements;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto &result = scan_results[i];
|
||||
@@ -126,7 +106,7 @@ void BluetoothProxy::flush_pending_advertisements() {
|
||||
if (this->advertisement_count_ == 0 || !api::global_api_server->is_connected() || this->api_connection_ == nullptr)
|
||||
return;
|
||||
|
||||
auto &advertisements = this->response_.advertisements;
|
||||
auto &advertisements = this->response_->advertisements;
|
||||
|
||||
// Return any items beyond advertisement_count_ to the pool
|
||||
if (advertisements.size() > this->advertisement_count_) {
|
||||
@@ -140,24 +120,37 @@ void BluetoothProxy::flush_pending_advertisements() {
|
||||
}
|
||||
|
||||
// Send the message
|
||||
this->api_connection_->send_message(this->response_, api::BluetoothLERawAdvertisementsResponse::MESSAGE_TYPE);
|
||||
this->api_connection_->send_message(*this->response_, api::BluetoothLERawAdvertisementsResponse::MESSAGE_TYPE);
|
||||
|
||||
// Reset count - existing items will be overwritten in next batch
|
||||
this->advertisement_count_ = 0;
|
||||
}
|
||||
|
||||
void BluetoothProxy::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Bluetooth Proxy:");
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Bluetooth Proxy:\n"
|
||||
" Active: %s\n"
|
||||
" Connections: %d",
|
||||
YESNO(this->active_), this->connection_count_);
|
||||
YESNO(this->active_), this->connections_.size());
|
||||
}
|
||||
|
||||
int BluetoothProxy::get_bluetooth_connections_free() {
|
||||
int free = 0;
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->address_ == 0) {
|
||||
free++;
|
||||
ESP_LOGV(TAG, "[%d] Free connection", connection->get_connection_index());
|
||||
} else {
|
||||
ESP_LOGV(TAG, "[%d] Used connection by [%s]", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
}
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
void BluetoothProxy::loop() {
|
||||
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr) {
|
||||
for (uint8_t i = 0; i < this->connection_count_; i++) {
|
||||
auto *connection = this->connections_[i];
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() != 0 && !connection->disconnect_pending()) {
|
||||
connection->disconnect();
|
||||
}
|
||||
@@ -180,8 +173,7 @@ esp32_ble_tracker::AdvertisementParserType BluetoothProxy::get_advertisement_par
|
||||
}
|
||||
|
||||
BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool reserve) {
|
||||
for (uint8_t i = 0; i < this->connection_count_; i++) {
|
||||
auto *connection = this->connections_[i];
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() == address)
|
||||
return connection;
|
||||
}
|
||||
@@ -189,10 +181,9 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
|
||||
if (!reserve)
|
||||
return nullptr;
|
||||
|
||||
for (uint8_t i = 0; i < this->connection_count_; i++) {
|
||||
auto *connection = this->connections_[i];
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->get_address() == 0) {
|
||||
connection->send_service_ = INIT_SENDING_SERVICES;
|
||||
connection->send_service_ = DONE_SENDING_SERVICES;
|
||||
connection->set_address(address);
|
||||
// All connections must start at INIT
|
||||
// We only set the state if we allocate the connection
|
||||
@@ -209,7 +200,8 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
|
||||
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
|
||||
switch (msg.request_type) {
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: {
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
|
||||
auto *connection = this->get_connection_(msg.address, true);
|
||||
if (connection == nullptr) {
|
||||
ESP_LOGW(TAG, "No free connections available");
|
||||
@@ -218,10 +210,23 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
|
||||
}
|
||||
if (connection->state() == espbt::ClientState::CONNECTED ||
|
||||
connection->state() == espbt::ClientState::ESTABLISHED) {
|
||||
this->log_connection_request_ignored_(connection, connection->state());
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
this->send_device_connection(msg.address, true);
|
||||
this->send_connections_free();
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::SEARCHING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::DISCOVERED) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::CONNECTING) {
|
||||
if (connection->disconnect_pending()) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request while pending disconnect, cancelling pending disconnect",
|
||||
@@ -229,18 +234,29 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
|
||||
connection->cancel_pending_disconnect();
|
||||
return;
|
||||
}
|
||||
this->log_connection_request_ignored_(connection, connection->state());
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
|
||||
connection->get_connection_index(), connection->address_str().c_str());
|
||||
return;
|
||||
} else if (connection->state() != espbt::ClientState::INIT) {
|
||||
this->log_connection_request_ignored_(connection, connection->state());
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
return;
|
||||
}
|
||||
if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE) {
|
||||
connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
|
||||
this->log_connection_info_(connection, "v3 with cache");
|
||||
} else { // BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
} else if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE) {
|
||||
connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
|
||||
this->log_connection_info_(connection, "v3 without cache");
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
|
||||
connection->address_str().c_str());
|
||||
} else {
|
||||
connection->set_connection_type(espbt::ConnectionType::V1);
|
||||
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
|
||||
}
|
||||
if (msg.has_address_type) {
|
||||
uint64_to_bd_addr(msg.address, connection->remote_bda_);
|
||||
@@ -302,18 +318,14 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
|
||||
|
||||
break;
|
||||
}
|
||||
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
|
||||
ESP_LOGE(TAG, "V1 connections removed");
|
||||
this->send_device_connection(msg.address, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
this->handle_gatt_not_connected_(msg.address, msg.handle, "read", "characteristic");
|
||||
ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected");
|
||||
this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -326,7 +338,8 @@ void BluetoothProxy::bluetooth_gatt_read(const api::BluetoothGATTReadRequest &ms
|
||||
void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
this->handle_gatt_not_connected_(msg.address, msg.handle, "write", "characteristic");
|
||||
ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected");
|
||||
this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -339,7 +352,8 @@ void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &
|
||||
void BluetoothProxy::bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
this->handle_gatt_not_connected_(msg.address, msg.handle, "read", "descriptor");
|
||||
ESP_LOGW(TAG, "Cannot read GATT descriptor, not connected");
|
||||
this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -352,7 +366,8 @@ void BluetoothProxy::bluetooth_gatt_read_descriptor(const api::BluetoothGATTRead
|
||||
void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
this->handle_gatt_not_connected_(msg.address, msg.handle, "write", "descriptor");
|
||||
ESP_LOGW(TAG, "Cannot write GATT descriptor, not connected");
|
||||
this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -365,7 +380,8 @@ void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWri
|
||||
void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr || !connection->connected()) {
|
||||
this->handle_gatt_not_connected_(msg.address, 0, "get", "services");
|
||||
ESP_LOGW(TAG, "Cannot get GATT services, not connected");
|
||||
this->send_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
if (!connection->service_count_) {
|
||||
@@ -373,14 +389,16 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer
|
||||
this->send_gatt_services_done(msg.address);
|
||||
return;
|
||||
}
|
||||
if (connection->send_service_ == INIT_SENDING_SERVICES) // Start sending services if not started yet
|
||||
if (connection->send_service_ ==
|
||||
DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them
|
||||
connection->send_service_ = 0;
|
||||
}
|
||||
|
||||
void BluetoothProxy::bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg) {
|
||||
auto *connection = this->get_connection_(msg.address, false);
|
||||
if (connection == nullptr) {
|
||||
this->handle_gatt_not_connected_(msg.address, msg.handle, "notify", "characteristic");
|
||||
ESP_LOGW(TAG, "Cannot notify GATT characteristic, not connected");
|
||||
this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -421,13 +439,17 @@ void BluetoothProxy::send_device_connection(uint64_t address, bool connected, ui
|
||||
this->api_connection_->send_message(call, api::BluetoothDeviceConnectionResponse::MESSAGE_TYPE);
|
||||
}
|
||||
void BluetoothProxy::send_connections_free() {
|
||||
if (this->api_connection_ != nullptr) {
|
||||
this->send_connections_free(this->api_connection_);
|
||||
if (this->api_connection_ == nullptr)
|
||||
return;
|
||||
api::BluetoothConnectionsFreeResponse call;
|
||||
call.free = this->get_bluetooth_connections_free();
|
||||
call.limit = this->get_bluetooth_connections_limit();
|
||||
for (auto *connection : this->connections_) {
|
||||
if (connection->address_ != 0) {
|
||||
call.allocated.push_back(connection->address_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothProxy::send_connections_free(api::APIConnection *api_connection) {
|
||||
api_connection->send_message(this->connections_free_response_, api::BluetoothConnectionsFreeResponse::MESSAGE_TYPE);
|
||||
this->api_connection_->send_message(call, api::BluetoothConnectionsFreeResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
void BluetoothProxy::send_gatt_services_done(uint64_t address) {
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
@@ -23,7 +22,6 @@ namespace esphome::bluetooth_proxy {
|
||||
|
||||
static const esp_err_t ESP_GATT_NOT_CONNECTED = -1;
|
||||
static const int DONE_SENDING_SERVICES = -2;
|
||||
static const int INIT_SENDING_SERVICES = -3;
|
||||
|
||||
using namespace esp32_ble_client;
|
||||
|
||||
@@ -51,7 +49,6 @@ enum BluetoothProxySubscriptionFlag : uint32_t {
|
||||
};
|
||||
|
||||
class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Component {
|
||||
friend class BluetoothConnection; // Allow connection to update connections_free_response_
|
||||
public:
|
||||
BluetoothProxy();
|
||||
#ifdef USE_ESP32_BLE_DEVICE
|
||||
@@ -65,10 +62,8 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
||||
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override;
|
||||
|
||||
void register_connection(BluetoothConnection *connection) {
|
||||
if (this->connection_count_ < BLUETOOTH_PROXY_MAX_CONNECTIONS) {
|
||||
this->connections_[this->connection_count_++] = connection;
|
||||
connection->proxy_ = this;
|
||||
}
|
||||
this->connections_.push_back(connection);
|
||||
connection->proxy_ = this;
|
||||
}
|
||||
|
||||
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg);
|
||||
@@ -79,13 +74,15 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
||||
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
|
||||
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
|
||||
|
||||
int get_bluetooth_connections_free();
|
||||
int get_bluetooth_connections_limit() { return this->connections_.size(); }
|
||||
|
||||
void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags);
|
||||
void unsubscribe_api_connection(api::APIConnection *api_connection);
|
||||
api::APIConnection *get_api_connection() { return this->api_connection_; }
|
||||
|
||||
void send_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK);
|
||||
void send_connections_free();
|
||||
void send_connections_free(api::APIConnection *api_connection);
|
||||
void send_gatt_services_done(uint64_t address);
|
||||
void send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error);
|
||||
void send_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK);
|
||||
@@ -137,33 +134,25 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
||||
void send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state);
|
||||
|
||||
BluetoothConnection *get_connection_(uint64_t address, bool reserve);
|
||||
void log_connection_request_ignored_(BluetoothConnection *connection, espbt::ClientState state);
|
||||
void log_connection_info_(BluetoothConnection *connection, const char *message);
|
||||
void log_not_connected_gatt_(const char *action, const char *type);
|
||||
void handle_gatt_not_connected_(uint64_t address, uint16_t handle, const char *action, const char *type);
|
||||
|
||||
// Memory optimized layout for 32-bit systems
|
||||
// Group 1: Pointers (4 bytes each, naturally aligned)
|
||||
api::APIConnection *api_connection_{nullptr};
|
||||
|
||||
// Group 2: Fixed-size array of connection pointers
|
||||
std::array<BluetoothConnection *, BLUETOOTH_PROXY_MAX_CONNECTIONS> connections_{};
|
||||
// Group 2: Container types (typically 12 bytes on 32-bit)
|
||||
std::vector<BluetoothConnection *> connections_{};
|
||||
|
||||
// BLE advertisement batching
|
||||
std::vector<api::BluetoothLERawAdvertisement> advertisement_pool_;
|
||||
api::BluetoothLERawAdvertisementsResponse response_;
|
||||
std::unique_ptr<api::BluetoothLERawAdvertisementsResponse> response_;
|
||||
|
||||
// Group 3: 4-byte types
|
||||
uint32_t last_advertisement_flush_time_{0};
|
||||
|
||||
// Pre-allocated response message - always ready to send
|
||||
api::BluetoothConnectionsFreeResponse connections_free_response_;
|
||||
|
||||
// Group 4: 1-byte types grouped together
|
||||
bool active_;
|
||||
uint8_t advertisement_count_{0};
|
||||
uint8_t connection_count_{0};
|
||||
// 3 bytes used, 1 byte padding
|
||||
// 2 bytes used, 2 bytes padding
|
||||
};
|
||||
|
||||
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
@@ -88,6 +88,7 @@ const char *oversampling_to_str(BME280Oversampling oversampling) { // NOLINT
|
||||
}
|
||||
|
||||
void BME280Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t chip_id = 0;
|
||||
|
||||
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
|
||||
|
@@ -28,7 +28,7 @@ const float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM = {0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
const float BME680_GAS_LOOKUP_TABLE_2[16] PROGMEM = {0.0, 0.0, 0.0, 0.0, 0.1, 0.7, 0.0, -0.8,
|
||||
-0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
[[maybe_unused]] static const char *oversampling_to_str(BME680Oversampling oversampling) {
|
||||
static const char *oversampling_to_str(BME680Oversampling oversampling) {
|
||||
switch (oversampling) {
|
||||
case BME680_OVERSAMPLING_NONE:
|
||||
return "None";
|
||||
@@ -47,7 +47,7 @@ const float BME680_GAS_LOOKUP_TABLE_2[16] PROGMEM = {0.0, 0.0, 0.0, 0.0, 0.1, 0
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static const char *iir_filter_to_str(BME680IIRFilter filter) {
|
||||
static const char *iir_filter_to_str(BME680IIRFilter filter) {
|
||||
switch (filter) {
|
||||
case BME680_IIR_FILTER_OFF:
|
||||
return "OFF";
|
||||
@@ -71,6 +71,7 @@ const float BME680_GAS_LOOKUP_TABLE_2[16] PROGMEM = {0.0, 0.0, 0.0, 0.0, 0.1, 0
|
||||
}
|
||||
|
||||
void BME680Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t chip_id;
|
||||
if (!this->read_byte(BME680_REGISTER_CHIPID, &chip_id) || chip_id != 0x61) {
|
||||
this->mark_failed();
|
||||
|
@@ -15,6 +15,8 @@ std::vector<BME680BSECComponent *>
|
||||
uint8_t BME680BSECComponent::work_buffer_[BSEC_MAX_WORKBUFFER_SIZE] = {0};
|
||||
|
||||
void BME680BSECComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->device_id_.c_str());
|
||||
|
||||
uint8_t new_idx = BME680BSECComponent::instances.size();
|
||||
BME680BSECComponent::instances.push_back(this);
|
||||
|
||||
|
@@ -21,6 +21,8 @@ static const char *const TAG = "bme68x_bsec2.sensor";
|
||||
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
|
||||
|
||||
void BME68xBSEC2Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
this->bsec_status_ = bsec_init_m(&this->bsec_instance_);
|
||||
if (this->bsec_status_ != BSEC_OK) {
|
||||
this->mark_failed();
|
||||
|
@@ -119,6 +119,7 @@ const float GRAVITY_EARTH = 9.80665f;
|
||||
void BMI160Component::internal_setup_(int stage) {
|
||||
switch (stage) {
|
||||
case 0:
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t chipid;
|
||||
if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) {
|
||||
this->mark_failed();
|
||||
|
@@ -20,6 +20,7 @@ void BMP085Component::update() {
|
||||
this->set_timeout("temperature", 5, [this]() { this->read_temperature_(); });
|
||||
}
|
||||
void BMP085Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t data[22];
|
||||
if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) {
|
||||
this->mark_failed();
|
||||
|
@@ -57,6 +57,7 @@ static const char *iir_filter_to_str(BMP280IIRFilter filter) {
|
||||
}
|
||||
|
||||
void BMP280Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
uint8_t chip_id = 0;
|
||||
|
||||
// Read the chip id twice, to work around a bug where the first read is 0.
|
||||
|
@@ -70,6 +70,7 @@ static const LogString *iir_filter_to_str(IIRFilter filter) {
|
||||
|
||||
void BMP3XXComponent::setup() {
|
||||
this->error_code_ = NONE;
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
// Call the Device base class "initialise" function
|
||||
if (!reset()) {
|
||||
ESP_LOGE(TAG, "Failed to reset");
|
||||
|
@@ -128,6 +128,8 @@ void BMP581Component::setup() {
|
||||
*/
|
||||
|
||||
this->error_code_ = NONE;
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
////////////////////
|
||||
// 1) Soft reboot //
|
||||
////////////////////
|
||||
|
@@ -15,6 +15,7 @@ static const uint8_t BP1658CJ_ADDR_START_5CH = 0x30;
|
||||
static const uint8_t BP1658CJ_DELAY = 2;
|
||||
|
||||
void BP1658CJ::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->data_pin_->setup();
|
||||
this->data_pin_->digital_write(false);
|
||||
this->clock_pin_->setup();
|
||||
|
@@ -20,6 +20,7 @@ static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
|
||||
static const uint8_t BP5758D_DELAY = 2;
|
||||
|
||||
void BP5758D::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
this->data_pin_->setup();
|
||||
this->data_pin_->digital_write(false);
|
||||
delayMicroseconds(BP5758D_DELAY);
|
||||
|
@@ -137,3 +137,4 @@ async def button_press_to_code(config, action_id, template_arg, args):
|
||||
@coroutine_with_priority(100.0)
|
||||
async def to_code(config):
|
||||
cg.add_global(button_ns.using)
|
||||
cg.add_define("USE_BUTTON")
|
||||
|
@@ -22,8 +22,9 @@ def validate_id(config):
|
||||
if CONF_CAN_ID in config:
|
||||
can_id = config[CONF_CAN_ID]
|
||||
id_ext = config[CONF_USE_EXTENDED_ID]
|
||||
if not id_ext and can_id > 0x7FF:
|
||||
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
|
||||
if not id_ext:
|
||||
if can_id > 0x7FF:
|
||||
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
|
||||
return config
|
||||
|
||||
|
||||
|
@@ -7,6 +7,7 @@ namespace canbus {
|
||||
static const char *const TAG = "canbus";
|
||||
|
||||
void Canbus::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
if (!this->setup_internal()) {
|
||||
ESP_LOGE(TAG, "setup error!");
|
||||
this->mark_failed();
|
||||
|
@@ -8,6 +8,8 @@ namespace cap1188 {
|
||||
static const char *const TAG = "cap1188";
|
||||
|
||||
void CAP1188Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
// Reset device using the reset pin
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup();
|
||||
|
@@ -14,7 +14,7 @@ from esphome.core import CORE, coroutine_with_priority
|
||||
|
||||
AUTO_LOAD = ["web_server_base", "ota.web_server"]
|
||||
DEPENDENCIES = ["wifi"]
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
CODEOWNERS = ["@OttoWinter"]
|
||||
|
||||
captive_portal_ns = cg.esphome_ns.namespace("captive_portal")
|
||||
CaptivePortal = captive_portal_ns.class_("CaptivePortal", cg.Component)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user