mirror of
https://github.com/esphome/esphome.git
synced 2025-11-03 00:21:56 +00:00
Compare commits
1079 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0760e99b7 | ||
|
|
18fecf8c09 | ||
|
|
414cf1b333 | ||
|
|
d10f891f51 | ||
|
|
b5927322e6 | ||
|
|
1cf4107e1c | ||
|
|
c12408326c | ||
|
|
4434e59e5a | ||
|
|
45180d98f6 | ||
|
|
44494ad18e | ||
|
|
1447536906 | ||
|
|
27ec517084 | ||
|
|
ce1f034bac | ||
|
|
f1f96f16e9 | ||
|
|
7665e9b076 | ||
|
|
227d94f38d | ||
|
|
b724ae9e0e | ||
|
|
df6cc14201 | ||
|
|
d981d7859d | ||
|
|
0f1ec515c1 | ||
|
|
78e18256f7 | ||
|
|
4899dfe642 | ||
|
|
d6b6e94059 | ||
|
|
310355a00b | ||
|
|
8cf26d6f3c | ||
|
|
b15a10f905 | ||
|
|
5dcf1debd7 | ||
|
|
9b57e1ac1d | ||
|
|
68683e3a50 | ||
|
|
d83324c4dc | ||
|
|
ecde4c1d2d | ||
|
|
bd8e470726 | ||
|
|
d2913fe627 | ||
|
|
43acc7dc2c | ||
|
|
e2a16d758b | ||
|
|
17ea0efb08 | ||
|
|
2fbd33267e | ||
|
|
cf3977f088 | ||
|
|
d20d4947ac | ||
|
|
7810ad40d7 | ||
|
|
7e1e799b3a | ||
|
|
dfafc41ce6 | ||
|
|
e460792c43 | ||
|
|
a9dc491a54 | ||
|
|
ac6693f177 | ||
|
|
c6742117d3 | ||
|
|
b5c47b9669 | ||
|
|
40df3aa55e | ||
|
|
393ca64d70 | ||
|
|
d3627f0972 | ||
|
|
124ab31f22 | ||
|
|
1b66fa5004 | ||
|
|
9494c27ad8 | ||
|
|
3facfa5c21 | ||
|
|
93ddce2e79 | ||
|
|
0bf6e21e1a | ||
|
|
6b7b076875 | ||
|
|
8d6ffb9169 | ||
|
|
e95d6041d8 | ||
|
|
0554b06b7e | ||
|
|
e3d9c44bdc | ||
|
|
e847766514 | ||
|
|
d4a8df04b8 | ||
|
|
4af4649e23 | ||
|
|
8bcddef39d | ||
|
|
4ac96ccea2 | ||
|
|
3c5de77ae9 | ||
|
|
a2925b1d37 | ||
|
|
73748e9e20 | ||
|
|
034b47c23a | ||
|
|
3e017efa30 | ||
|
|
aca56fcdcc | ||
|
|
75c9823899 | ||
|
|
c8c0bd3351 | ||
|
|
e1cdeb7c8f | ||
|
|
7f97f42552 | ||
|
|
aa7f3569ec | ||
|
|
2d0a08442e | ||
|
|
d2380756b2 | ||
|
|
e778a445d9 | ||
|
|
ded86493c2 | ||
|
|
4d72eb42a5 | ||
|
|
267f0587c6 | ||
|
|
4a374a466a | ||
|
|
b27a328d1e | ||
|
|
d94e9d92ca | ||
|
|
36c2e770bf | ||
|
|
79040c116d | ||
|
|
4aac76c549 | ||
|
|
0ea97df1af | ||
|
|
92e66a2764 | ||
|
|
925e3cb6c9 | ||
|
|
6757acba56 | ||
|
|
5cc91cdd95 | ||
|
|
2b41886819 | ||
|
|
72c6efd6a0 | ||
|
|
a1f1804112 | ||
|
|
a8b1ceb4e9 | ||
|
|
4fb0f7f8c6 | ||
|
|
958cadeca8 | ||
|
|
00f2655f1a | ||
|
|
074f5029eb | ||
|
|
615d591367 | ||
|
|
e236c53f05 | ||
|
|
10c7055b41 | ||
|
|
a127e60e1b | ||
|
|
66a3361e9d | ||
|
|
13cfe11a19 | ||
|
|
6d65671f92 | ||
|
|
f2eafa8fbe | ||
|
|
e4ca3b18cc | ||
|
|
84698ae888 | ||
|
|
fd6d6cfb6c | ||
|
|
8cad9dfc83 | ||
|
|
5e2f33fde5 | ||
|
|
029ac75a04 | ||
|
|
3aa5953cd9 | ||
|
|
582d90ad72 | ||
|
|
bbb0105c2f | ||
|
|
37d17feecf | ||
|
|
4bf5faf808 | ||
|
|
ddedc1cd76 | ||
|
|
1bb90f304c | ||
|
|
efc6a8df35 | ||
|
|
e35f90d6e4 | ||
|
|
11518364a1 | ||
|
|
05420291ce | ||
|
|
442faf92c6 | ||
|
|
62c68f4d60 | ||
|
|
c301ae3645 | ||
|
|
3d2d681a7b | ||
|
|
a45646af1b | ||
|
|
27185265f6 | ||
|
|
a9b7d98194 | ||
|
|
ed4a7210d3 | ||
|
|
351ea04517 | ||
|
|
86a8e1f4a6 | ||
|
|
1cf3424ebe | ||
|
|
a19f0c0db0 | ||
|
|
530df91044 | ||
|
|
c16c0b11cb | ||
|
|
74556b28a8 | ||
|
|
48340d41d6 | ||
|
|
6306348379 | ||
|
|
b1f1329cee | ||
|
|
75dff1e102 | ||
|
|
fe55f3a43d | ||
|
|
657fd9d0d5 | ||
|
|
1511a6ebcd | ||
|
|
ecac26aeba | ||
|
|
19bf9b1e36 | ||
|
|
119a6920f2 | ||
|
|
8237e13c44 | ||
|
|
53b60ac817 | ||
|
|
a18ab748fd | ||
|
|
917488bbc3 | ||
|
|
7e376ae952 | ||
|
|
57a1c207c2 | ||
|
|
50e8e92f0b | ||
|
|
ff4fd497c4 | ||
|
|
33b1a853b9 | ||
|
|
f2df542cb1 | ||
|
|
ecbbf2d3f4 | ||
|
|
b76c7a0131 | ||
|
|
0b0984f9a0 | ||
|
|
9767856784 | ||
|
|
c1f09684e6 | ||
|
|
22b384363b | ||
|
|
5b23331751 | ||
|
|
7a2bb32843 | ||
|
|
c0a4e07e5a | ||
|
|
322158cccb | ||
|
|
8db3b59e0f | ||
|
|
1691976587 | ||
|
|
60e6b4d21e | ||
|
|
5750591df2 | ||
|
|
0d50caa179 | ||
|
|
8b06135b41 | ||
|
|
a75da54455 | ||
|
|
de7f6c3f5f | ||
|
|
4245480656 | ||
|
|
1824c8131e | ||
|
|
573ea55187 | ||
|
|
b48b5d6cc7 | ||
|
|
4e9606d2e0 | ||
|
|
78500fa933 | ||
|
|
9c69b98a49 | ||
|
|
e6d8ef98d3 | ||
|
|
3f1af1690b | ||
|
|
39af967433 | ||
|
|
83b5e01a28 | ||
|
|
1eacbd50fa | ||
|
|
84374b6b1e | ||
|
|
391316c9b5 | ||
|
|
705c62ebd7 | ||
|
|
cb520c00a5 | ||
|
|
2f24138345 | ||
|
|
96512b80cc | ||
|
|
fcb9b51978 | ||
|
|
9bf7c97775 | ||
|
|
24bf3674f3 | ||
|
|
f408f1a368 | ||
|
|
7d8d563c62 | ||
|
|
0a1f705fda | ||
|
|
1952c1880b | ||
|
|
c47dc09d34 | ||
|
|
db3096c6e1 | ||
|
|
b03967dac1 | ||
|
|
bcae2596a6 | ||
|
|
fc0347c86c | ||
|
|
eef578f4b8 | ||
|
|
d9563d4de1 | ||
|
|
cc7e2bf8db | ||
|
|
5d98e2923b | ||
|
|
d4e232f267 | ||
|
|
cc45945fcf | ||
|
|
07197d12f6 | ||
|
|
7b0a298497 | ||
|
|
21679cf2ba | ||
|
|
0c24d951ff | ||
|
|
92e44b8238 | ||
|
|
4be7cd12a1 | ||
|
|
34387adbcd | ||
|
|
dee4d0ccb7 | ||
|
|
c6885c1bf4 | ||
|
|
8b8efb57af | ||
|
|
499e120aa4 | ||
|
|
6f198a4736 | ||
|
|
f500f448b1 | ||
|
|
6ad9baa870 | ||
|
|
f843925301 | ||
|
|
4a3b628946 | ||
|
|
4ffdc38cf5 | ||
|
|
f83f1bff19 | ||
|
|
9370ff3dfa | ||
|
|
2053b02c61 | ||
|
|
f34e797a0d | ||
|
|
30a2fc1273 | ||
|
|
48da5ef1c4 | ||
|
|
7209dd8bae | ||
|
|
ab736c89bb | ||
|
|
6911639617 | ||
|
|
dbbbba3cf8 | ||
|
|
16e523ca68 | ||
|
|
3b2bbd306f | ||
|
|
54caed36f7 | ||
|
|
dfcccda69e | ||
|
|
de352c1609 | ||
|
|
c30068fc97 | ||
|
|
f28f712827 | ||
|
|
b9720d0715 | ||
|
|
47b3267ed4 | ||
|
|
e16ba2adb5 | ||
|
|
0a19b1e32c | ||
|
|
bae9a950c0 | ||
|
|
b63ade298f | ||
|
|
f117d4f50a | ||
|
|
6e4267b797 | ||
|
|
2dd032475b | ||
|
|
db0ed055dd | ||
|
|
106c1bfac2 | ||
|
|
eb2a0f45db | ||
|
|
2b4fdd6c39 | ||
|
|
3669320398 | ||
|
|
d706f40ce1 | ||
|
|
027284c29c | ||
|
|
c55e01ff3f | ||
|
|
a59ce7bfa2 | ||
|
|
a6196267c9 | ||
|
|
eb664b99ba | ||
|
|
8414bb9a7a | ||
|
|
ccef7c322f | ||
|
|
120327866f | ||
|
|
bc5c2d4eb4 | ||
|
|
d5ff8f6117 | ||
|
|
ad0d6f6337 | ||
|
|
873de13b3d | ||
|
|
56de8e5cc4 | ||
|
|
73c82862cf | ||
|
|
75573a3ed1 | ||
|
|
1166d93805 | ||
|
|
ac112a32c9 | ||
|
|
cee45c1221 | ||
|
|
fb56b5388e | ||
|
|
ed42cefeee | ||
|
|
9052947a71 | ||
|
|
53e0af18fb | ||
|
|
c5f59fad62 | ||
|
|
b089a4ea80 | ||
|
|
72b2943332 | ||
|
|
4ec0ef7548 | ||
|
|
25bc6761f6 | ||
|
|
81b6562c25 | ||
|
|
ae74189fc2 | ||
|
|
555bba7698 | ||
|
|
294901fbe9 | ||
|
|
ec576bf9f9 | ||
|
|
9273e3775b | ||
|
|
ce5cedb466 | ||
|
|
b184b01600 | ||
|
|
81b4078871 | ||
|
|
d067c8f80b | ||
|
|
9e516efe10 | ||
|
|
366e29439e | ||
|
|
1c9c700d7f | ||
|
|
b2e6b9d31f | ||
|
|
7623f63846 | ||
|
|
2bfaf9dce3 | ||
|
|
5c2c1560bb | ||
|
|
8975b4b3f6 | ||
|
|
20da03f8c6 | ||
|
|
ef26677b67 | ||
|
|
91925b1826 | ||
|
|
1f33ad037d | ||
|
|
fef60e335e | ||
|
|
195c78846f | ||
|
|
0f9c956c04 | ||
|
|
7258a82875 | ||
|
|
c1f696c32a | ||
|
|
f2b63d9c67 | ||
|
|
7896a7783b | ||
|
|
621771e1ee | ||
|
|
2b032e8606 | ||
|
|
5e1b724697 | ||
|
|
e6db61c2f0 | ||
|
|
c2e198311c | ||
|
|
d874626662 | ||
|
|
eead72333e | ||
|
|
f7096ab78e | ||
|
|
98f8feb625 | ||
|
|
9944ca414e | ||
|
|
719c212009 | ||
|
|
65030e1c37 | ||
|
|
3f88b63920 | ||
|
|
70f1c71a9f | ||
|
|
816df5ad47 | ||
|
|
f7b1602adf | ||
|
|
7e88eea532 | ||
|
|
d1cdfd3b72 | ||
|
|
d6a03d48f5 | ||
|
|
d453b42b1a | ||
|
|
7c19b961e2 | ||
|
|
147b113b62 | ||
|
|
d924702825 | ||
|
|
e8784ba383 | ||
|
|
e3a454d1a6 | ||
|
|
392dc8b0db | ||
|
|
2f62426f09 | ||
|
|
58fda40389 | ||
|
|
6a73699a38 | ||
|
|
3bd6456fbe | ||
|
|
608be4e050 | ||
|
|
10f590324b | ||
|
|
cb2d9e4bec | ||
|
|
9e3ee28744 | ||
|
|
472dcebf2c | ||
|
|
39f0f748bf | ||
|
|
9efe59a984 | ||
|
|
fcb02af782 | ||
|
|
9f30f53c6b | ||
|
|
2f18ae00c5 | ||
|
|
27a339fa12 | ||
|
|
3aeef1afd4 | ||
|
|
a45ee8f4ac | ||
|
|
31b62d7dca | ||
|
|
22f81475db | ||
|
|
cc7cf73d59 | ||
|
|
9682e60a25 | ||
|
|
2c2e68123a | ||
|
|
fcec7d45cb | ||
|
|
7c8f502e7e | ||
|
|
dc17c47634 | ||
|
|
3d927c2f44 | ||
|
|
0ae61410d2 | ||
|
|
2455589f61 | ||
|
|
c6afae0da5 | ||
|
|
3155f02be6 | ||
|
|
4fa0e860ad | ||
|
|
8c122aa372 | ||
|
|
5a0bf9fee9 | ||
|
|
dc794918ed | ||
|
|
02b15dbc4a | ||
|
|
ed316b1ce3 | ||
|
|
d7858f16c1 | ||
|
|
291deb12ad | ||
|
|
3e110681c9 | ||
|
|
65fbfa2097 | ||
|
|
16ebf9da4c | ||
|
|
2c76381fcd | ||
|
|
90683223dd | ||
|
|
de79171815 | ||
|
|
1554c5700e | ||
|
|
5cf257b251 | ||
|
|
04883e14f6 | ||
|
|
0a649c184f | ||
|
|
0e66c899ce | ||
|
|
e7d236f939 | ||
|
|
fae4d03473 | ||
|
|
fd8b9fb028 | ||
|
|
97bd3e7320 | ||
|
|
dfca2f88d3 | ||
|
|
8cad93de37 | ||
|
|
bdf1813b3a | ||
|
|
45b6c93f5f | ||
|
|
e5b8dd7f2d | ||
|
|
a1c8b8092b | ||
|
|
109ca2406d | ||
|
|
3a689112fd | ||
|
|
40e0cd0f03 | ||
|
|
bf4d3df906 | ||
|
|
0e30c49e3f | ||
|
|
e61a01f7bb | ||
|
|
f8640cf2cd | ||
|
|
4bcfeb6e33 | ||
|
|
a5d4ca0f6d | ||
|
|
85faecb2fd | ||
|
|
991fc54994 | ||
|
|
2de891dc32 | ||
|
|
9865cb7f55 | ||
|
|
f97252b93a | ||
|
|
6124531479 | ||
|
|
b8549d323c | ||
|
|
01adece673 | ||
|
|
0220934e4c | ||
|
|
ca09693efa | ||
|
|
e96d7483b3 | ||
|
|
f2c4f018de | ||
|
|
237c7dd169 | ||
|
|
b781b8d77d | ||
|
|
60b7d1c8a1 | ||
|
|
8161222b33 | ||
|
|
1000c4466f | ||
|
|
60717b074e | ||
|
|
c3fba97b4c | ||
|
|
d93f35701f | ||
|
|
702b60ce66 | ||
|
|
f8ce597918 | ||
|
|
22e0a944c8 | ||
|
|
3a134ef009 | ||
|
|
96e8cb66b6 | ||
|
|
615288c151 | ||
|
|
6153bcc6ad | ||
|
|
e87edcc77a | ||
|
|
a21c3e8e2d | ||
|
|
d7576f67e8 | ||
|
|
138de643a2 | ||
|
|
f30e54d177 | ||
|
|
41b5cb06d3 | ||
|
|
4ac72d7d08 | ||
|
|
06ac4980ba | ||
|
|
ccbfa20bb9 | ||
|
|
58cd754e07 | ||
|
|
d1263e583b | ||
|
|
67c911c37f | ||
|
|
288e3c3e3e | ||
|
|
a84378c6c2 | ||
|
|
b6073408f4 | ||
|
|
b2d91ac5de | ||
|
|
8bf34e09f4 | ||
|
|
be914f2c15 | ||
|
|
8bb670521d | ||
|
|
225b3c1494 | ||
|
|
4bf94e0757 | ||
|
|
3b21d1d81e | ||
|
|
5ec1588110 | ||
|
|
71387be72e | ||
|
|
98171c9f49 | ||
|
|
a6c999dea0 | ||
|
|
bf15b1d302 | ||
|
|
f422fabab4 | ||
|
|
01b130ec59 | ||
|
|
48a1797e72 | ||
|
|
b34d24735a | ||
|
|
fe38b36c26 | ||
|
|
03fca8d91e | ||
|
|
9f9980e338 | ||
|
|
19900b004b | ||
|
|
a8ff0a8913 | ||
|
|
45861456f1 | ||
|
|
44b335e7e3 | ||
|
|
de23bbace2 | ||
|
|
edff9ae322 | ||
|
|
3c2766448d | ||
|
|
786c8b6cfe | ||
|
|
e8de6a3a67 | ||
|
|
3c320c4c83 | ||
|
|
3b83f967e4 | ||
|
|
5e96b8ef7c | ||
|
|
5df0e82c37 | ||
|
|
fd57b21aff | ||
|
|
6087183a0c | ||
|
|
01b7c4200e | ||
|
|
7171286c3c | ||
|
|
2d58239b74 | ||
|
|
6b52f62531 | ||
|
|
1001d9c04e | ||
|
|
d220d41182 | ||
|
|
c3a8972550 | ||
|
|
263b603188 | ||
|
|
584b722e7e | ||
|
|
05edfd0e82 | ||
|
|
16249c02a5 | ||
|
|
e8ff36d1f3 | ||
|
|
ed443c6153 | ||
|
|
f4a84765cd | ||
|
|
106de3530d | ||
|
|
119c3f6f46 | ||
|
|
d2c1c7507c | ||
|
|
efdb3d1f40 | ||
|
|
8095db6715 | ||
|
|
ce2e161b08 | ||
|
|
9dbc32b85f | ||
|
|
66226abb48 | ||
|
|
34bef2f2ca | ||
|
|
6ef93452f5 | ||
|
|
fdd4ca6837 | ||
|
|
9655362f23 | ||
|
|
130c9fad22 | ||
|
|
3de0b601bf | ||
|
|
91560ae4e9 | ||
|
|
fd6135aebb | ||
|
|
68ea59f3ae | ||
|
|
e5fe5d1249 | ||
|
|
9a69769a7e | ||
|
|
63b42f3608 | ||
|
|
d56107e97f | ||
|
|
33f296e05b | ||
|
|
3572c62315 | ||
|
|
97e067a277 | ||
|
|
1444cddda9 | ||
|
|
5f56cf3128 | ||
|
|
5c4e83ebdc | ||
|
|
91f1c25fcc | ||
|
|
47a7a239ae | ||
|
|
fb9984e21f | ||
|
|
b2db524366 | ||
|
|
ab8674a5c7 | ||
|
|
d1c85fc3fa | ||
|
|
55ad45e3ee | ||
|
|
f6e5a8cb2a | ||
|
|
7a91ca9809 | ||
|
|
71dd04b09e | ||
|
|
7deabbb512 | ||
|
|
625a575e49 | ||
|
|
df4d0da221 | ||
|
|
6b23b7cad7 | ||
|
|
cea7deab91 | ||
|
|
c61abf6aca | ||
|
|
917bbc669c | ||
|
|
0ac4c055de | ||
|
|
78b55d86e9 | ||
|
|
aaf50fc2e6 | ||
|
|
6a8f4e92df | ||
|
|
6d267fda01 | ||
|
|
88943103a2 | ||
|
|
e557dc7208 | ||
|
|
3558806b0e | ||
|
|
f1e8cc2cf0 | ||
|
|
6236db1a27 | ||
|
|
f4b0917239 | ||
|
|
a5e3cd1a42 | ||
|
|
b3cca5dcb6 | ||
|
|
49465223a4 | ||
|
|
15f0e54cbf | ||
|
|
ed8f343aad | ||
|
|
cbd8d70431 | ||
|
|
9ff187c3f8 | ||
|
|
be473b97c4 | ||
|
|
9a5f865eea | ||
|
|
790280ace9 | ||
|
|
8ba207fc7f | ||
|
|
d66b2a1778 | ||
|
|
e3f2562047 | ||
|
|
f77118a90c | ||
|
|
041eb8f6cc | ||
|
|
733a84df75 | ||
|
|
acd0b50b40 | ||
|
|
635851807a | ||
|
|
89fd367297 | ||
|
|
60e46d485e | ||
|
|
5bf0c92318 | ||
|
|
39d493c278 | ||
|
|
d2ce62aa13 | ||
|
|
c8eb30ef27 | ||
|
|
c317422ed7 | ||
|
|
614eb81ad7 | ||
|
|
219c5953f1 | ||
|
|
5d712c73ea | ||
|
|
7097b7677e | ||
|
|
7a4cf13e0c | ||
|
|
4788a6182e | ||
|
|
e3dad7c632 | ||
|
|
1b4156646e | ||
|
|
31ad75d01b | ||
|
|
aa2eb29274 | ||
|
|
22eb4f9cb9 | ||
|
|
3acc8e7479 | ||
|
|
2650441013 | ||
|
|
71697df2b6 | ||
|
|
acd55b9601 | ||
|
|
0907de8662 | ||
|
|
15eb9605a8 | ||
|
|
6d5cb866db | ||
|
|
768490089e | ||
|
|
4d66fab360 | ||
|
|
bd6bc283b6 | ||
|
|
3120a0ba83 | ||
|
|
b2199d5464 | ||
|
|
84bac8356a | ||
|
|
2819166539 | ||
|
|
8fa18ca7c7 | ||
|
|
63290a265c | ||
|
|
b854e17995 | ||
|
|
5dec9d88f6 | ||
|
|
3d0a85ee78 | ||
|
|
ac3cdf487f | ||
|
|
a47e92f2bc | ||
|
|
fc15ddfa91 | ||
|
|
d546ef941f | ||
|
|
b4bbe3d7b5 | ||
|
|
5561d4eaeb | ||
|
|
0f6dab394a | ||
|
|
adc8c1aa38 | ||
|
|
3a82f500d4 | ||
|
|
7d1d4831a8 | ||
|
|
43539f2dbf | ||
|
|
df6830110d | ||
|
|
1a98e882dc | ||
|
|
c943d84036 | ||
|
|
d07a6704d5 | ||
|
|
8cfcd5904c | ||
|
|
fb8846bb45 | ||
|
|
0d0733dd94 | ||
|
|
1a524a5a50 | ||
|
|
1a2288cccf | ||
|
|
8df27d4c3f | ||
|
|
0688deca6b | ||
|
|
01a4443b6c | ||
|
|
e008b054cb | ||
|
|
a67d58948d | ||
|
|
84c051d097 | ||
|
|
b918abfd54 | ||
|
|
7f41b7cd93 | ||
|
|
4759b4fe2e | ||
|
|
e2c8e69d12 | ||
|
|
1cf213dad8 | ||
|
|
aeb81e547b | ||
|
|
479f7703a2 | ||
|
|
c7dc396b6d | ||
|
|
917e8e155c | ||
|
|
80e3030811 | ||
|
|
a97e3d827d | ||
|
|
029014d9d6 | ||
|
|
e4c2922536 | ||
|
|
7133ae6aaa | ||
|
|
2f7f0ff3a1 | ||
|
|
df853bf61e | ||
|
|
f0ac753f9b | ||
|
|
4d56a975e6 | ||
|
|
d56c53c848 | ||
|
|
f83b16320d | ||
|
|
ac10e27f08 | ||
|
|
34df7a6072 | ||
|
|
e2cddf1005 | ||
|
|
ced423748e | ||
|
|
77fb02729e | ||
|
|
fef39b9fbe | ||
|
|
02810105fb | ||
|
|
baad92515b | ||
|
|
ab86ddcf02 | ||
|
|
bf8eddb13b | ||
|
|
e5eaf7a3fe | ||
|
|
50f32a3aa5 | ||
|
|
eb878710c1 | ||
|
|
311980e0e4 | ||
|
|
df73170e5a | ||
|
|
a12c6b5f35 | ||
|
|
522646c64d | ||
|
|
4791093e48 | ||
|
|
599a455150 | ||
|
|
2deef16ebe | ||
|
|
989b7be99b | ||
|
|
cd473e1395 | ||
|
|
e246ebfb2e | ||
|
|
8546ae56da | ||
|
|
9e227b0192 | ||
|
|
ba7737e9f8 | ||
|
|
98aa3d51ed | ||
|
|
e7cfb5492e | ||
|
|
9ed136dc3a | ||
|
|
9217216723 | ||
|
|
936c408a58 | ||
|
|
54427eac9a | ||
|
|
e809488cc0 | ||
|
|
ed26c57d99 | ||
|
|
2a49811f6e | ||
|
|
c95acd2568 | ||
|
|
6a4e0cf667 | ||
|
|
04f4dd8a22 | ||
|
|
f33d829ce9 | ||
|
|
578671ea94 | ||
|
|
d10300c330 | ||
|
|
e0555e140f | ||
|
|
093989406f | ||
|
|
cdb16f08f6 | ||
|
|
53139c293b | ||
|
|
6a8bdcc315 | ||
|
|
fe535939a3 | ||
|
|
09e6c11d73 | ||
|
|
8112bdfaa8 | ||
|
|
f7db9aaa9f | ||
|
|
435f972357 | ||
|
|
f82b46c16b | ||
|
|
bca96f91b2 | ||
|
|
6f83a49c63 | ||
|
|
72cce391ab | ||
|
|
ccc13cc9e1 | ||
|
|
020b2c05c8 | ||
|
|
4c37c17df1 | ||
|
|
8f67acadd8 | ||
|
|
ca13c4c1a6 | ||
|
|
d0c646c721 | ||
|
|
8a055675af | ||
|
|
28d2949ebe | ||
|
|
c4a0015997 | ||
|
|
f564be6aea | ||
|
|
988f15e6af | ||
|
|
37b6d442bd | ||
|
|
fb2467f6f0 | ||
|
|
29045b0435 | ||
|
|
311a48c64e | ||
|
|
01b3815f27 | ||
|
|
b0d1c801bd | ||
|
|
5aaac06f5b | ||
|
|
34adbf0588 | ||
|
|
0a4213182e | ||
|
|
b0c0258e70 | ||
|
|
8110e591d0 | ||
|
|
fe05d7aec1 | ||
|
|
57f5884070 | ||
|
|
f329c74a15 | ||
|
|
7c86f3fa9e | ||
|
|
203b8b01bf | ||
|
|
8a1034a92f | ||
|
|
aa0c2dedd9 | ||
|
|
d045908e05 | ||
|
|
f002a23d2d | ||
|
|
29d6d0a906 | ||
|
|
c8b58b5c23 | ||
|
|
01bfafc5f1 | ||
|
|
8c9948bb56 | ||
|
|
2d1abaa68e | ||
|
|
664a3df0b4 | ||
|
|
9ff893881c | ||
|
|
94f6c6861a | ||
|
|
b1d614e6c4 | ||
|
|
7fceb070e5 | ||
|
|
06440d0202 | ||
|
|
0ecf9f4f2f | ||
|
|
5c7c0834c0 | ||
|
|
f3a25de11d | ||
|
|
041bef8bcd | ||
|
|
8998c5f6dd | ||
|
|
6e83790308 | ||
|
|
d2d4eb4eae | ||
|
|
5942a3898c | ||
|
|
93421f0fa7 | ||
|
|
3a9ab50dd2 | ||
|
|
5abd91d6d5 | ||
|
|
c3da42516b | ||
|
|
6cb5cd48c2 | ||
|
|
ec1fae6883 | ||
|
|
746fd1122f | ||
|
|
9663760ec5 | ||
|
|
a3d73d1e23 | ||
|
|
d63e14a4b6 | ||
|
|
03944e6cd8 | ||
|
|
0d1028be2e | ||
|
|
6a85259e4d | ||
|
|
ebca936b7e | ||
|
|
31c4551890 | ||
|
|
dd470d4197 | ||
|
|
612822490b | ||
|
|
f8969605e8 | ||
|
|
dd24ffa24e | ||
|
|
d0dda48932 | ||
|
|
6349b5f654 | ||
|
|
a6ff02a3cf | ||
|
|
4f57bf786b | ||
|
|
6221f6d47d | ||
|
|
a922efeafa | ||
|
|
5aa42e5e66 | ||
|
|
708672ec7e | ||
|
|
d2cefbf224 | ||
|
|
adb7aa6950 | ||
|
|
77f322166e | ||
|
|
f3f6e54818 | ||
|
|
fb0fec1f25 | ||
|
|
b66af9fb4d | ||
|
|
6617d576a7 | ||
|
|
cd35ead890 | ||
|
|
9dc804ee27 | ||
|
|
a8ceeaa7b0 | ||
|
|
7092f7663e | ||
|
|
d9d2edeb08 | ||
|
|
dda1ddcb26 | ||
|
|
f0c890f160 | ||
|
|
4f52d43347 | ||
|
|
0ed7db979b | ||
|
|
9c78049359 | ||
|
|
7882105661 | ||
|
|
c000e1d6dd | ||
|
|
420dacb22d | ||
|
|
ae2f6ad4d1 | ||
|
|
2c28d79bf8 | ||
|
|
c5069edc78 | ||
|
|
282d9e138c | ||
|
|
72fcf2cbe1 | ||
|
|
6f49f5465b | ||
|
|
17b8bd8316 | ||
|
|
9b6b9c1fa2 | ||
|
|
609a2ca592 | ||
|
|
6dabf24bf3 | ||
|
|
7e88938932 | ||
|
|
c707e64685 | ||
|
|
a639690716 | ||
|
|
01222dbab7 | ||
|
|
93e2506279 | ||
|
|
f62d5d3b9d | ||
|
|
0665acd190 | ||
|
|
fea05e9d33 | ||
|
|
7a03c7d56f | ||
|
|
2dc2aec954 | ||
|
|
39c6c2417a | ||
|
|
ff72d6a146 | ||
|
|
603d0d0c7c | ||
|
|
28883f711b | ||
|
|
e914828add | ||
|
|
c1480029fb | ||
|
|
40f622949e | ||
|
|
63096ac2bc | ||
|
|
03d5a0ec1d | ||
|
|
1c873e0034 | ||
|
|
bcb47c306c | ||
|
|
01c4d3c225 | ||
|
|
c2aaae4818 | ||
|
|
3f678e218d | ||
|
|
c2a59cb476 | ||
|
|
f8a1bd4e79 | ||
|
|
d6e039a1d1 | ||
|
|
0f1a7c2b69 | ||
|
|
40ad9f4911 | ||
|
|
4116caff6a | ||
|
|
0b69f72315 | ||
|
|
c569f5ddcf | ||
|
|
62f9e181e0 | ||
|
|
235a97ea10 | ||
|
|
e541ae400c | ||
|
|
4822abde86 | ||
|
|
b7e52812f8 | ||
|
|
69118120d9 | ||
|
|
7cba0c6fb0 | ||
|
|
5fac67ce15 | ||
|
|
98c733108e | ||
|
|
782186e13d | ||
|
|
4e1f6518e8 | ||
|
|
53e0fe8e51 | ||
|
|
0e547390da | ||
|
|
86b52df839 | ||
|
|
d685fdf54a | ||
|
|
d9caab4108 | ||
|
|
44b68f140e | ||
|
|
3a3d97dfa7 | ||
|
|
47898b527c | ||
|
|
a35f36ad39 | ||
|
|
d13a397f8e | ||
|
|
df999723f8 | ||
|
|
8236e840a7 | ||
|
|
e5b3625f73 | ||
|
|
2e4645310b | ||
|
|
50a32b387e | ||
|
|
2059283707 | ||
|
|
8e3af515c9 | ||
|
|
6f88f0ea3f | ||
|
|
d2f37cf3f9 | ||
|
|
7c30d6254e | ||
|
|
64fb39a653 | ||
|
|
91895aa70c | ||
|
|
68dfaf238b | ||
|
|
ebf13a0ba0 | ||
|
|
2bff9937b7 | ||
|
|
256395c28d | ||
|
|
3346bc8bba | ||
|
|
6fe22a7e62 | ||
|
|
757b98748b | ||
|
|
7a778f3f33 | ||
|
|
993044c870 | ||
|
|
a8c1b63edb | ||
|
|
db7d946e1b | ||
|
|
41d9059a2f | ||
|
|
e26e0d7c01 | ||
|
|
ad41c07a1f | ||
|
|
9576d246ee | ||
|
|
988d3ea8ba | ||
|
|
0767b92b62 | ||
|
|
5732f3b044 | ||
|
|
712115b6ce | ||
|
|
9283559c6b | ||
|
|
6b393438e9 | ||
|
|
2064abe16d | ||
|
|
b605982f94 | ||
|
|
343b9ab455 | ||
|
|
dcb226b202 | ||
|
|
2243021b58 | ||
|
|
d5134e88b1 | ||
|
|
c59adf612f | ||
|
|
93b628d9a8 | ||
|
|
6bac551d9f | ||
|
|
70a35656e4 | ||
|
|
047c18eac0 | ||
|
|
b4a86ce6cf | ||
|
|
a82d8ea0c3 | ||
|
|
b778eed419 | ||
|
|
ad57faa9a9 | ||
|
|
a9b5e8d036 | ||
|
|
8be704e591 | ||
|
|
b622a8fa58 | ||
|
|
a519e5c475 | ||
|
|
d620b6dd5e | ||
|
|
99335d986e | ||
|
|
7895cd92cd | ||
|
|
8b2c032da6 | ||
|
|
da336247eb | ||
|
|
dabd27d4be | ||
|
|
fdda47db6e | ||
|
|
efa6fd03e5 | ||
|
|
9e3e34acf5 | ||
|
|
a2d0c1bf18 | ||
|
|
7663716ae8 | ||
|
|
c2cacb3478 | ||
|
|
84666b54b9 | ||
|
|
2b91c23bf3 | ||
|
|
3297267a16 | ||
|
|
a9e653724c | ||
|
|
5e79a1f500 | ||
|
|
d4ff98680a | ||
|
|
ba8d255cb4 | ||
|
|
06f4ad922c | ||
|
|
bff06e448b | ||
|
|
d48ffa2913 | ||
|
|
d97c3a7e01 | ||
|
|
0b1161f7ef | ||
|
|
061e1a471d | ||
|
|
a39d874600 | ||
|
|
de96376565 | ||
|
|
c54c20ab3c | ||
|
|
70fafa473b | ||
|
|
2e436eae6b | ||
|
|
fd7e861ff5 | ||
|
|
792108686c | ||
|
|
fa1b5117fd | ||
|
|
b0bd9e0a34 | ||
|
|
05dc97099a | ||
|
|
9de61fcf58 | ||
|
|
fc7348d46d | ||
|
|
8be2456c7e | ||
|
|
bb5f7249a6 | ||
|
|
7f7175b184 | ||
|
|
cf5c640ae4 | ||
|
|
6b9371d105 | ||
|
|
9a82057303 | ||
|
|
48584e94c4 | ||
|
|
fc94a5d0ee | ||
|
|
d8024a5928 | ||
|
|
2034ab4f6c | ||
|
|
24029cc918 | ||
|
|
9a9d5964ee | ||
|
|
4e4a512107 | ||
|
|
0729ed538e | ||
|
|
24b75b7ed6 | ||
|
|
58b70b42dd | ||
|
|
1496bc1b07 | ||
|
|
bfbf88b2ea | ||
|
|
e621b938e3 | ||
|
|
ec3618ecb8 | ||
|
|
792a24f38d | ||
|
|
652e8a015b | ||
|
|
59e6e798dd | ||
|
|
e5c2dbc7ec | ||
|
|
756f71c382 | ||
|
|
b7535693fa | ||
|
|
06a3505698 | ||
|
|
0372d17a11 | ||
|
|
4525588116 | ||
|
|
68e957c147 | ||
|
|
99f5ed1461 | ||
|
|
59f67796dc | ||
|
|
aafdfa933e | ||
|
|
3208c8ed1e | ||
|
|
6bf733e24e | ||
|
|
65d3e8fbfc | ||
|
|
a29d65d47c | ||
|
|
efa8f0730d | ||
|
|
0af1edefff | ||
|
|
023d26f521 | ||
|
|
5068619f1b | ||
|
|
5b2457af0b | ||
|
|
900b4f1af9 | ||
|
|
4c22a98b0b | ||
|
|
3b8ca80900 | ||
|
|
1ef6fd8fb0 | ||
|
|
942b0de7fd | ||
|
|
859cca49d1 | ||
|
|
dc6eff83ea | ||
|
|
38ff66debd | ||
|
|
1d2e0f74ea | ||
|
|
bf60e40d0b | ||
|
|
c9094ca537 | ||
|
|
68b3fd6b8f | ||
|
|
9323b3a248 | ||
|
|
b55e9329d9 | ||
|
|
a5b4105971 | ||
|
|
d1feaa935d | ||
|
|
6919930aaa | ||
|
|
69633826bb | ||
|
|
771162bfb1 | ||
|
|
ba785e29e9 | ||
|
|
2c7b104f4a | ||
|
|
78951c197a | ||
|
|
07c1cf7137 | ||
|
|
d26141151a | ||
|
|
f59dbe4a88 | ||
|
|
8dae7f8225 | ||
|
|
5811389891 | ||
|
|
debcaf6fb7 | ||
|
|
b8d10a62c2 | ||
|
|
d2b209234f | ||
|
|
34c9d8be50 | ||
|
|
ae57ad0c81 | ||
|
|
0c1520dd9c | ||
|
|
d594f43ebd | ||
|
|
125c693e3f | ||
|
|
ad2f857e15 | ||
|
|
e445d6aada | ||
|
|
88fbb0ffbb | ||
|
|
231908fe9f | ||
|
|
f137cc10f4 | ||
|
|
1a8f8adc2a | ||
|
|
7a242bb4ed | ||
|
|
3b8bb09ae3 | ||
|
|
140db85d21 | ||
|
|
ccce4b19e8 | ||
|
|
8cb9be7560 | ||
|
|
953f0569fb | ||
|
|
34c229fd33 | ||
|
|
958ad0d750 | ||
|
|
36ddd9dd69 | ||
|
|
38259c96c9 | ||
|
|
c054fb8a2c | ||
|
|
5a0b8328d8 | ||
|
|
ffa19426d7 | ||
|
|
c123804294 | ||
|
|
4e24551b90 | ||
|
|
51cb5da7f0 | ||
|
|
41f84447cc | ||
|
|
ce073a704b | ||
|
|
113232ebb6 | ||
|
|
a13a1225b7 | ||
|
|
0ec84be5da | ||
|
|
b1cefb7e3e | ||
|
|
cc0c1c08b9 | ||
|
|
3a67884451 | ||
|
|
72e716cdf1 | ||
|
|
40e06c9819 | ||
|
|
ad6c5ff11d | ||
|
|
335512e232 | ||
|
|
2622e59b0b | ||
|
|
35e6a13cd1 | ||
|
|
b48490badc |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ESPHome Dev",
|
"name": "ESPHome Dev",
|
||||||
"image": "esphome/esphome-lint:dev",
|
"image": "ghcr.io/esphome/esphome-lint:dev",
|
||||||
"postCreateCommand": [
|
"postCreateCommand": [
|
||||||
"script/devcontainer-post-create"
|
"script/devcontainer-post-create"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -25,10 +25,9 @@ indent_size = 2
|
|||||||
[*.{yaml,yml}]
|
[*.{yaml,yml}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
quote_type = single
|
quote_type = double
|
||||||
|
|
||||||
# JSON
|
# JSON
|
||||||
[*.json]
|
[*.json]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
|||||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
---
|
||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
custom: https://www.nabucasa.com
|
custom: https://www.nabucasa.com
|
||||||
|
|||||||
9
.github/ISSUE_TEMPLATE/config.yml
vendored
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
---
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Issue Tracker
|
- name: Issue Tracker
|
||||||
@@ -5,8 +6,10 @@ contact_links:
|
|||||||
about: Please create bug reports in the dedicated issue tracker.
|
about: Please create bug reports in the dedicated issue tracker.
|
||||||
- name: Feature Request Tracker
|
- name: Feature Request Tracker
|
||||||
url: https://github.com/esphome/feature-requests
|
url: https://github.com/esphome/feature-requests
|
||||||
about: Please create feature requests in the dedicated feature request tracker.
|
about: |
|
||||||
|
Please create feature requests in the dedicated feature request tracker.
|
||||||
- name: Frequently Asked Question
|
- name: Frequently Asked Question
|
||||||
url: https://esphome.io/guides/faq.html
|
url: https://esphome.io/guides/faq.html
|
||||||
about: Please view the FAQ for common questions and what to include in a bug report.
|
about: |
|
||||||
|
Please view the FAQ for common questions and what
|
||||||
|
to include in a bug report.
|
||||||
|
|||||||
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
|||||||
# What does this implement/fix?
|
# What does this implement/fix?
|
||||||
|
|
||||||
Quick description and explanation of changes
|
<!-- Quick description and explanation of changes -->
|
||||||
|
|
||||||
## Types of changes
|
## Types of changes
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ Quick description and explanation of changes
|
|||||||
- [ ] ESP32
|
- [ ] ESP32
|
||||||
- [ ] ESP32 IDF
|
- [ ] ESP32 IDF
|
||||||
- [ ] ESP8266
|
- [ ] ESP8266
|
||||||
|
- [ ] RP2040
|
||||||
|
|
||||||
## Example entry for `config.yaml`:
|
## Example entry for `config.yaml`:
|
||||||
<!--
|
<!--
|
||||||
@@ -35,6 +36,6 @@ Quick description and explanation of changes
|
|||||||
## Checklist:
|
## Checklist:
|
||||||
- [ ] The code change is tested and works locally.
|
- [ ] The code change is tested and works locally.
|
||||||
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
|
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
|
||||||
|
|
||||||
If user exposed functionality or configuration variables are added/changed:
|
If user exposed functionality or configuration variables are added/changed:
|
||||||
- [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
|
- [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
|
||||||
|
|||||||
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -1,9 +1,15 @@
|
|||||||
|
---
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "pip"
|
- package-ecosystem: pip
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: daily
|
||||||
ignore:
|
ignore:
|
||||||
# Hypotehsis is only used for testing and is updated quite often
|
# Hypotehsis is only used for testing and is updated quite often
|
||||||
- dependency-name: hypothesis
|
- dependency-name: hypothesis
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
|||||||
57
.github/workflows/ci-docker.yml
vendored
57
.github/workflows/ci-docker.yml
vendored
@@ -1,21 +1,23 @@
|
|||||||
|
---
|
||||||
name: CI for docker images
|
name: CI for docker images
|
||||||
|
|
||||||
# Only run when docker paths change
|
# Only run when docker paths change
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [dev, beta, release]
|
branches: [dev, beta, release]
|
||||||
paths:
|
paths:
|
||||||
- 'docker/**'
|
- "docker/**"
|
||||||
- '.github/workflows/**'
|
- ".github/workflows/**"
|
||||||
- 'requirements*.txt'
|
- "requirements*.txt"
|
||||||
- 'platformio.ini'
|
- "platformio.ini"
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'docker/**'
|
- "docker/**"
|
||||||
- '.github/workflows/**'
|
- ".github/workflows/**"
|
||||||
- 'requirements*.txt'
|
- "requirements*.txt"
|
||||||
- 'platformio.ini'
|
- "platformio.ini"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -26,28 +28,29 @@ jobs:
|
|||||||
name: Build docker containers
|
name: Build docker containers
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [amd64, armv7, aarch64]
|
arch: [amd64, armv7, aarch64]
|
||||||
build_type: ["ha-addon", "docker", "lint"]
|
build_type: ["ha-addon", "docker", "lint"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.9'
|
python-version: "3.9"
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Set TAG
|
- name: Set TAG
|
||||||
run: |
|
run: |
|
||||||
echo "TAG=check" >> $GITHUB_ENV
|
echo "TAG=check" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Run build
|
- name: Run build
|
||||||
run: |
|
run: |
|
||||||
docker/build.py \
|
docker/build.py \
|
||||||
--tag "${TAG}" \
|
--tag "${TAG}" \
|
||||||
--arch "${{ matrix.arch }}" \
|
--arch "${{ matrix.arch }}" \
|
||||||
--build-type "${{ matrix.build_type }}" \
|
--build-type "${{ matrix.build_type }}" \
|
||||||
build
|
build
|
||||||
|
|||||||
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
@@ -1,5 +1,7 @@
|
|||||||
|
---
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [dev, beta, release]
|
branches: [dev, beta, release]
|
||||||
@@ -10,6 +12,7 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
# yamllint disable-line rule:line-length
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
@@ -45,6 +48,14 @@ jobs:
|
|||||||
file: tests/test5.yaml
|
file: tests/test5.yaml
|
||||||
name: Test tests/test5.yaml
|
name: Test tests/test5.yaml
|
||||||
pio_cache_key: test5
|
pio_cache_key: test5
|
||||||
|
- id: test
|
||||||
|
file: tests/test6.yaml
|
||||||
|
name: Test tests/test6.yaml
|
||||||
|
pio_cache_key: test6
|
||||||
|
- id: test
|
||||||
|
file: tests/test7.yaml
|
||||||
|
name: Test tests/test7.yaml
|
||||||
|
pio_cache_key: test7
|
||||||
- id: pytest
|
- id: pytest
|
||||||
name: Run pytest
|
name: Run pytest
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
@@ -73,24 +84,28 @@ jobs:
|
|||||||
name: Run script/clang-tidy for ESP32 IDF
|
name: Run script/clang-tidy for ESP32 IDF
|
||||||
options: --environment esp32-idf-tidy --grep USE_ESP_IDF
|
options: --environment esp32-idf-tidy --grep USE_ESP_IDF
|
||||||
pio_cache_key: tidyesp32-idf
|
pio_cache_key: tidyesp32-idf
|
||||||
|
- id: yamllint
|
||||||
|
name: Run yamllint
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: '3.7'
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Cache virtualenv
|
- name: Cache virtualenv
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: .venv
|
path: .venv
|
||||||
|
# yamllint disable-line rule:line-length
|
||||||
key: venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements*.txt') }}
|
key: venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements*.txt') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
venv-${{ steps.python.outputs.python-version }}-
|
venv-${{ steps.python.outputs.python-version }}-
|
||||||
|
|
||||||
- name: Set up virtualenv
|
- name: Set up virtualenv
|
||||||
|
# yamllint disable rule:line-length
|
||||||
run: |
|
run: |
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
@@ -99,12 +114,14 @@ jobs:
|
|||||||
pip install -e .
|
pip install -e .
|
||||||
echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH
|
echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH
|
||||||
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> $GITHUB_ENV
|
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> $GITHUB_ENV
|
||||||
|
# yamllint enable rule:line-length
|
||||||
|
|
||||||
# Use per check platformio cache because checks use different parts
|
# Use per check platformio cache because checks use different parts
|
||||||
- name: Cache platformio
|
- name: Cache platformio
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
|
# yamllint disable-line rule:line-length
|
||||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||||
if: matrix.id == 'test' || matrix.id == 'clang-tidy'
|
if: matrix.id == 'test' || matrix.id == 'clang-tidy'
|
||||||
|
|
||||||
@@ -131,7 +148,7 @@ jobs:
|
|||||||
if: matrix.id == 'ci-custom'
|
if: matrix.id == 'ci-custom'
|
||||||
|
|
||||||
- name: Lint Python
|
- name: Lint Python
|
||||||
run: script/lint-python
|
run: script/lint-python -a
|
||||||
if: matrix.id == 'lint-python'
|
if: matrix.id == 'lint-python'
|
||||||
|
|
||||||
- run: esphome compile ${{ matrix.file }}
|
- run: esphome compile ${{ matrix.file }}
|
||||||
@@ -145,8 +162,9 @@ jobs:
|
|||||||
pytest -vv --tb=native tests
|
pytest -vv --tb=native tests
|
||||||
if: matrix.id == 'pytest'
|
if: matrix.id == 'pytest'
|
||||||
|
|
||||||
# Also run git-diff-index so that the step is marked as failed on formatting errors,
|
# Also run git-diff-index so that the step is marked as failed on
|
||||||
# since clang-format doesn't do anything but change files if -i is passed.
|
# formatting errors, since clang-format doesn't do anything but
|
||||||
|
# change files if -i is passed.
|
||||||
- name: Run clang-format
|
- name: Run clang-format
|
||||||
run: |
|
run: |
|
||||||
script/clang-format -i
|
script/clang-format -i
|
||||||
@@ -161,6 +179,11 @@ jobs:
|
|||||||
# Also cache libdeps, store them in a ~/.platformio subfolder
|
# Also cache libdeps, store them in a ~/.platformio subfolder
|
||||||
PLATFORMIO_LIBDEPS_DIR: ~/.platformio/libdeps
|
PLATFORMIO_LIBDEPS_DIR: ~/.platformio/libdeps
|
||||||
|
|
||||||
|
- name: Run yamllint
|
||||||
|
if: matrix.id == 'yamllint'
|
||||||
|
uses: frenck/action-yamllint@v1.3.1
|
||||||
|
|
||||||
- name: Suggested changes
|
- name: Suggested changes
|
||||||
run: script/ci-suggest-changes
|
run: script/ci-suggest-changes
|
||||||
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format')
|
# yamllint disable-line rule:line-length
|
||||||
|
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format' || matrix.id == 'lint-python')
|
||||||
|
|||||||
6
.github/workflows/lock.yml
vendored
6
.github/workflows/lock.yml
vendored
@@ -1,8 +1,10 @@
|
|||||||
|
---
|
||||||
name: Lock
|
name: Lock
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '30 0 * * *'
|
- cron: "30 0 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -16,7 +18,7 @@ jobs:
|
|||||||
lock:
|
lock:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v3
|
- uses: dessant/lock-threads@v4
|
||||||
with:
|
with:
|
||||||
pr-inactive-days: "1"
|
pr-inactive-days: "1"
|
||||||
pr-lock-reason: ""
|
pr-lock-reason: ""
|
||||||
|
|||||||
165
.github/workflows/release.yml
vendored
165
.github/workflows/release.yml
vendored
@@ -1,5 +1,7 @@
|
|||||||
|
---
|
||||||
name: Publish Release
|
name: Publish Release
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
@@ -17,9 +19,10 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
tag: ${{ steps.tag.outputs.tag }}
|
tag: ${{ steps.tag.outputs.tag }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Get tag
|
- name: Get tag
|
||||||
id: tag
|
id: tag
|
||||||
|
# yamllint disable rule:line-length
|
||||||
run: |
|
run: |
|
||||||
if [[ "$GITHUB_EVENT_NAME" = "release" ]]; then
|
if [[ "$GITHUB_EVENT_NAME" = "release" ]]; then
|
||||||
TAG="${GITHUB_REF#refs/tags/}"
|
TAG="${GITHUB_REF#refs/tags/}"
|
||||||
@@ -27,19 +30,24 @@ jobs:
|
|||||||
TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
|
TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
|
||||||
today="$(date --utc '+%Y%m%d')"
|
today="$(date --utc '+%Y%m%d')"
|
||||||
TAG="${TAG}${today}"
|
TAG="${TAG}${today}"
|
||||||
|
BRANCH=${GITHUB_REF#refs/heads/}
|
||||||
|
if [[ "$BRANCH" != "dev" ]]; then
|
||||||
|
TAG="${TAG}-${BRANCH}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo "::set-output name=tag::${TAG}"
|
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||||
|
# yamllint enable rule:line-length
|
||||||
|
|
||||||
deploy-pypi:
|
deploy-pypi:
|
||||||
name: Build and publish to PyPi
|
name: Build and publish to PyPi
|
||||||
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
|
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: "3.x"
|
||||||
- name: Set up python environment
|
- name: Set up python environment
|
||||||
run: |
|
run: |
|
||||||
script/setup
|
script/setup
|
||||||
@@ -53,102 +61,95 @@ jobs:
|
|||||||
run: twine upload dist/*
|
run: twine upload dist/*
|
||||||
|
|
||||||
deploy-docker:
|
deploy-docker:
|
||||||
name: Build and publish docker containers
|
name: Build and publish ESPHome ${{ matrix.image.title}}
|
||||||
if: github.repository == 'esphome/esphome'
|
if: github.repository == 'esphome/esphome'
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: ${{ matrix.image.title == 'lint' }}
|
||||||
needs: [init]
|
needs: [init]
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [amd64, armv7, aarch64]
|
image:
|
||||||
build_type: ["ha-addon", "docker", "lint"]
|
- title: "ha-addon"
|
||||||
|
suffix: "hassio"
|
||||||
|
target: "hassio"
|
||||||
|
baseimg: "hassio"
|
||||||
|
- title: "docker"
|
||||||
|
suffix: ""
|
||||||
|
target: "docker"
|
||||||
|
baseimg: "docker"
|
||||||
|
- title: "lint"
|
||||||
|
suffix: "lint"
|
||||||
|
target: "lint"
|
||||||
|
baseimg: "docker"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.9'
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Log in to docker hub
|
- name: Log in to docker hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USER }}
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
- name: Log in to the GitHub container registry
|
- name: Log in to the GitHub container registry
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Generate short tags
|
||||||
run: |
|
id: tags
|
||||||
docker/build.py \
|
run: |
|
||||||
--tag "${{ needs.init.outputs.tag }}" \
|
docker/generate_tags.py \
|
||||||
--arch "${{ matrix.arch }}" \
|
--tag "${{ needs.init.outputs.tag }}" \
|
||||||
--build-type "${{ matrix.build_type }}" \
|
--suffix "${{ matrix.image.suffix }}"
|
||||||
build \
|
|
||||||
--push
|
|
||||||
|
|
||||||
deploy-docker-manifest:
|
- name: Build and push
|
||||||
if: github.repository == 'esphome/esphome'
|
uses: docker/build-push-action@v3
|
||||||
permissions:
|
with:
|
||||||
contents: read
|
context: .
|
||||||
packages: write
|
file: ./docker/Dockerfile
|
||||||
runs-on: ubuntu-latest
|
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||||
needs: [init, deploy-docker]
|
target: ${{ matrix.image.target }}
|
||||||
strategy:
|
push: true
|
||||||
matrix:
|
# yamllint disable rule:line-length
|
||||||
build_type: ["ha-addon", "docker", "lint"]
|
cache-from: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }}
|
||||||
steps:
|
cache-to: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }},mode=max
|
||||||
- uses: actions/checkout@v2
|
# yamllint enable rule:line-length
|
||||||
- name: Set up Python
|
tags: ${{ steps.tags.outputs.tags }}
|
||||||
uses: actions/setup-python@v2
|
build-args: |
|
||||||
with:
|
BASEIMGTYPE=${{ matrix.image.baseimg }}
|
||||||
python-version: '3.9'
|
BUILD_VERSION=${{ needs.init.outputs.tag }}
|
||||||
- name: Enable experimental manifest support
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.docker
|
|
||||||
echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
|
|
||||||
|
|
||||||
- name: Log in to docker hub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USER }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
- name: Log in to the GitHub container registry
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Run manifest
|
|
||||||
run: |
|
|
||||||
docker/build.py \
|
|
||||||
--tag "${{ needs.init.outputs.tag }}" \
|
|
||||||
--build-type "${{ matrix.build_type }}" \
|
|
||||||
manifest
|
|
||||||
|
|
||||||
deploy-ha-addon-repo:
|
deploy-ha-addon-repo:
|
||||||
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
|
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [deploy-docker]
|
needs: [deploy-docker]
|
||||||
steps:
|
steps:
|
||||||
- env:
|
- name: Trigger Workflow
|
||||||
TOKEN: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
|
uses: actions/github-script@v6
|
||||||
run: |
|
with:
|
||||||
TAG="${GITHUB_REF#refs/tags/}"
|
github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
|
||||||
curl \
|
script: |
|
||||||
-u ":$TOKEN" \
|
github.rest.actions.createWorkflowDispatch({
|
||||||
-X POST \
|
owner: "esphome",
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
repo: "home-assistant-addon",
|
||||||
https://api.github.com/repos/esphome/home-assistant-addon/actions/workflows/bump-version.yml/dispatches \
|
workflow_id: "bump-version.yml",
|
||||||
-d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}"
|
ref: "main",
|
||||||
|
inputs: {
|
||||||
|
version: "${{ github.event.release.tag_name }}",
|
||||||
|
content: ${{ toJSON(github.event.release.body) }}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
11
.github/workflows/stale.yml
vendored
11
.github/workflows/stale.yml
vendored
@@ -1,8 +1,10 @@
|
|||||||
|
---
|
||||||
name: Stale
|
name: Stale
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '30 0 * * *'
|
- cron: "30 0 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -16,7 +18,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v4
|
- uses: actions/stale@v7
|
||||||
with:
|
with:
|
||||||
days-before-pr-stale: 90
|
days-before-pr-stale: 90
|
||||||
days-before-pr-close: 7
|
days-before-pr-close: 7
|
||||||
@@ -31,11 +33,12 @@ jobs:
|
|||||||
and will be closed if no further activity occurs within 7 days.
|
and will be closed if no further activity occurs within 7 days.
|
||||||
Thank you for your contributions.
|
Thank you for your contributions.
|
||||||
|
|
||||||
# Use stale to automatically close issues with a reference to the issue tracker
|
# Use stale to automatically close issues with a
|
||||||
|
# reference to the issue tracker
|
||||||
close-issues:
|
close-issues:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v4
|
- uses: actions/stale@v7
|
||||||
with:
|
with:
|
||||||
days-before-pr-stale: -1
|
days-before-pr-stale: -1
|
||||||
days-before-pr-close: -1
|
days-before-pr-close: -1
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -77,6 +77,7 @@ venv/
|
|||||||
ENV/
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
|
venv-*/
|
||||||
|
|
||||||
# mypy
|
# mypy
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
@@ -127,3 +128,5 @@ tests/.esphome/
|
|||||||
|
|
||||||
sdkconfig.*
|
sdkconfig.*
|
||||||
!sdkconfig.defaults
|
!sdkconfig.defaults
|
||||||
|
|
||||||
|
.tests/
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
ports:
|
|
||||||
- port: 6052
|
|
||||||
onOpen: open-preview
|
|
||||||
tasks:
|
|
||||||
- before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup
|
|
||||||
command: python -m esphome dashboard config
|
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
|
---
|
||||||
# See https://pre-commit.com for more information
|
# See https://pre-commit.com for more information
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/ambv/black
|
- repo: https://github.com/ambv/black
|
||||||
rev: 22.1.0
|
rev: 22.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args:
|
args:
|
||||||
- --safe
|
- --safe
|
||||||
- --quiet
|
- --quiet
|
||||||
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
|
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
|
||||||
- repo: https://gitlab.com/pycqa/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 4.0.1
|
rev: 6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
@@ -25,3 +26,8 @@ repos:
|
|||||||
- --branch=dev
|
- --branch=dev
|
||||||
- --branch=release
|
- --branch=release
|
||||||
- --branch=beta
|
- --branch=beta
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v3.3.0
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: [--py39-plus]
|
||||||
|
|||||||
81
CODEOWNERS
81
CODEOWNERS
@@ -13,12 +13,14 @@ esphome/core/* @esphome/core
|
|||||||
# Integrations
|
# Integrations
|
||||||
esphome/components/ac_dimmer/* @glmnet
|
esphome/components/ac_dimmer/* @glmnet
|
||||||
esphome/components/adc/* @esphome/core
|
esphome/components/adc/* @esphome/core
|
||||||
|
esphome/components/adc128s102/* @DeerMaximum
|
||||||
esphome/components/addressable_light/* @justfalter
|
esphome/components/addressable_light/* @justfalter
|
||||||
esphome/components/airthings_ble/* @jeromelaban
|
esphome/components/airthings_ble/* @jeromelaban
|
||||||
esphome/components/airthings_wave_mini/* @ncareau
|
esphome/components/airthings_wave_mini/* @ncareau
|
||||||
esphome/components/airthings_wave_plus/* @jeromelaban
|
esphome/components/airthings_wave_plus/* @jeromelaban
|
||||||
esphome/components/am43/* @buxtronix
|
esphome/components/am43/* @buxtronix
|
||||||
esphome/components/am43/cover/* @buxtronix
|
esphome/components/am43/cover/* @buxtronix
|
||||||
|
esphome/components/analog_threshold/* @ianchi
|
||||||
esphome/components/animation/* @syndlex
|
esphome/components/animation/* @syndlex
|
||||||
esphome/components/anova/* @buxtronix
|
esphome/components/anova/* @buxtronix
|
||||||
esphome/components/api/* @OttoWinter
|
esphome/components/api/* @OttoWinter
|
||||||
@@ -27,11 +29,20 @@ esphome/components/atc_mithermometer/* @ahpohl
|
|||||||
esphome/components/b_parasite/* @rbaron
|
esphome/components/b_parasite/* @rbaron
|
||||||
esphome/components/ballu/* @bazuchan
|
esphome/components/ballu/* @bazuchan
|
||||||
esphome/components/bang_bang/* @OttoWinter
|
esphome/components/bang_bang/* @OttoWinter
|
||||||
|
esphome/components/bedjet/* @jhansche
|
||||||
|
esphome/components/bedjet/climate/* @jhansche
|
||||||
|
esphome/components/bedjet/fan/* @jhansche
|
||||||
|
esphome/components/bh1750/* @OttoWinter
|
||||||
esphome/components/binary_sensor/* @esphome/core
|
esphome/components/binary_sensor/* @esphome/core
|
||||||
|
esphome/components/bl0939/* @ziceva
|
||||||
esphome/components/bl0940/* @tobias-
|
esphome/components/bl0940/* @tobias-
|
||||||
|
esphome/components/bl0942/* @dbuezas
|
||||||
esphome/components/ble_client/* @buxtronix
|
esphome/components/ble_client/* @buxtronix
|
||||||
|
esphome/components/bluetooth_proxy/* @jesserockz
|
||||||
esphome/components/bme680_bsec/* @trvrnrth
|
esphome/components/bme680_bsec/* @trvrnrth
|
||||||
esphome/components/bmp3xx/* @martgras
|
esphome/components/bmp3xx/* @martgras
|
||||||
|
esphome/components/bp1658cj/* @Cossid
|
||||||
|
esphome/components/bp5758d/* @Cossid
|
||||||
esphome/components/button/* @esphome/core
|
esphome/components/button/* @esphome/core
|
||||||
esphome/components/canbus/* @danielschramm @mvturnho
|
esphome/components/canbus/* @danielschramm @mvturnho
|
||||||
esphome/components/cap1188/* @MrEditor97
|
esphome/components/cap1188/* @MrEditor97
|
||||||
@@ -42,29 +53,42 @@ esphome/components/climate/* @esphome/core
|
|||||||
esphome/components/climate_ir/* @glmnet
|
esphome/components/climate_ir/* @glmnet
|
||||||
esphome/components/color_temperature/* @jesserockz
|
esphome/components/color_temperature/* @jesserockz
|
||||||
esphome/components/coolix/* @glmnet
|
esphome/components/coolix/* @glmnet
|
||||||
|
esphome/components/copy/* @OttoWinter
|
||||||
esphome/components/cover/* @esphome/core
|
esphome/components/cover/* @esphome/core
|
||||||
esphome/components/cs5460a/* @balrog-kun
|
esphome/components/cs5460a/* @balrog-kun
|
||||||
esphome/components/cse7761/* @berfenger
|
esphome/components/cse7761/* @berfenger
|
||||||
esphome/components/ct_clamp/* @jesserockz
|
esphome/components/ct_clamp/* @jesserockz
|
||||||
esphome/components/current_based/* @djwmarcx
|
esphome/components/current_based/* @djwmarcx
|
||||||
|
esphome/components/dac7678/* @NickB1
|
||||||
|
esphome/components/daikin_brc/* @hagak
|
||||||
esphome/components/daly_bms/* @s1lvi0
|
esphome/components/daly_bms/* @s1lvi0
|
||||||
esphome/components/dashboard_import/* @esphome/core
|
esphome/components/dashboard_import/* @esphome/core
|
||||||
esphome/components/debug/* @OttoWinter
|
esphome/components/debug/* @OttoWinter
|
||||||
|
esphome/components/delonghi/* @grob6000
|
||||||
esphome/components/dfplayer/* @glmnet
|
esphome/components/dfplayer/* @glmnet
|
||||||
esphome/components/dht/* @OttoWinter
|
esphome/components/dht/* @OttoWinter
|
||||||
|
esphome/components/display_menu_base/* @numo68
|
||||||
|
esphome/components/dps310/* @kbx81
|
||||||
esphome/components/ds1307/* @badbadc0ffee
|
esphome/components/ds1307/* @badbadc0ffee
|
||||||
esphome/components/dsmr/* @glmnet @zuidwijk
|
esphome/components/dsmr/* @glmnet @zuidwijk
|
||||||
|
esphome/components/ee895/* @Stock-M
|
||||||
esphome/components/ektf2232/* @jesserockz
|
esphome/components/ektf2232/* @jesserockz
|
||||||
|
esphome/components/ens210/* @itn3rd77
|
||||||
esphome/components/esp32/* @esphome/core
|
esphome/components/esp32/* @esphome/core
|
||||||
esphome/components/esp32_ble/* @jesserockz
|
esphome/components/esp32_ble/* @jesserockz
|
||||||
|
esphome/components/esp32_ble_client/* @jesserockz
|
||||||
esphome/components/esp32_ble_server/* @jesserockz
|
esphome/components/esp32_ble_server/* @jesserockz
|
||||||
esphome/components/esp32_camera_web_server/* @ayufan
|
esphome/components/esp32_camera_web_server/* @ayufan
|
||||||
esphome/components/esp32_can/* @Sympatron
|
esphome/components/esp32_can/* @Sympatron
|
||||||
esphome/components/esp32_improv/* @jesserockz
|
esphome/components/esp32_improv/* @jesserockz
|
||||||
esphome/components/esp8266/* @esphome/core
|
esphome/components/esp8266/* @esphome/core
|
||||||
|
esphome/components/ethernet_info/* @gtjadsonsantos
|
||||||
esphome/components/exposure_notifications/* @OttoWinter
|
esphome/components/exposure_notifications/* @OttoWinter
|
||||||
esphome/components/ezo/* @ssieb
|
esphome/components/ezo/* @ssieb
|
||||||
|
esphome/components/ezo_pmp/* @carlos-sarmiento
|
||||||
|
esphome/components/factory_reset/* @anatoly-savchenkov
|
||||||
esphome/components/fastled_base/* @OttoWinter
|
esphome/components/fastled_base/* @OttoWinter
|
||||||
|
esphome/components/feedback/* @ianchi
|
||||||
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
||||||
esphome/components/globals/* @esphome/core
|
esphome/components/globals/* @esphome/core
|
||||||
esphome/components/gpio/* @esphome/core
|
esphome/components/gpio/* @esphome/core
|
||||||
@@ -77,8 +101,13 @@ esphome/components/hbridge/light/* @DotNetDann
|
|||||||
esphome/components/heatpumpir/* @rob-deutsch
|
esphome/components/heatpumpir/* @rob-deutsch
|
||||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||||
esphome/components/homeassistant/* @OttoWinter
|
esphome/components/homeassistant/* @OttoWinter
|
||||||
|
esphome/components/honeywellabp/* @RubyBailey
|
||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
||||||
|
esphome/components/hte501/* @Stock-M
|
||||||
|
esphome/components/hydreon_rgxx/* @functionpointer
|
||||||
esphome/components/i2c/* @esphome/core
|
esphome/components/i2c/* @esphome/core
|
||||||
|
esphome/components/i2s_audio/* @jesserockz
|
||||||
|
esphome/components/improv_base/* @esphome/core
|
||||||
esphome/components/improv_serial/* @esphome/core
|
esphome/components/improv_serial/* @esphome/core
|
||||||
esphome/components/ina260/* @MrEditor97
|
esphome/components/ina260/* @MrEditor97
|
||||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
|
esphome/components/inkbird_ibsth1_mini/* @fkirill
|
||||||
@@ -87,12 +116,19 @@ esphome/components/integration/* @OttoWinter
|
|||||||
esphome/components/interval/* @esphome/core
|
esphome/components/interval/* @esphome/core
|
||||||
esphome/components/json/* @OttoWinter
|
esphome/components/json/* @OttoWinter
|
||||||
esphome/components/kalman_combinator/* @Cat-Ion
|
esphome/components/kalman_combinator/* @Cat-Ion
|
||||||
|
esphome/components/key_collector/* @ssieb
|
||||||
|
esphome/components/key_provider/* @ssieb
|
||||||
|
esphome/components/lcd_menu/* @numo68
|
||||||
|
esphome/components/ld2410/* @sebcaps
|
||||||
esphome/components/ledc/* @OttoWinter
|
esphome/components/ledc/* @OttoWinter
|
||||||
esphome/components/light/* @esphome/core
|
esphome/components/light/* @esphome/core
|
||||||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||||
esphome/components/lock/* @esphome/core
|
esphome/components/lock/* @esphome/core
|
||||||
esphome/components/logger/* @esphome/core
|
esphome/components/logger/* @esphome/core
|
||||||
esphome/components/ltr390/* @sjtrny
|
esphome/components/ltr390/* @sjtrny
|
||||||
|
esphome/components/matrix_keypad/* @ssieb
|
||||||
|
esphome/components/max31865/* @DAVe3283
|
||||||
|
esphome/components/max44009/* @berfenger
|
||||||
esphome/components/max7219digit/* @rspaargaren
|
esphome/components/max7219digit/* @rspaargaren
|
||||||
esphome/components/max9611/* @mckaymatthew
|
esphome/components/max9611/* @mckaymatthew
|
||||||
esphome/components/mcp23008/* @jesserockz
|
esphome/components/mcp23008/* @jesserockz
|
||||||
@@ -104,10 +140,14 @@ esphome/components/mcp23x17_base/* @jesserockz
|
|||||||
esphome/components/mcp23xxx_base/* @jesserockz
|
esphome/components/mcp23xxx_base/* @jesserockz
|
||||||
esphome/components/mcp2515/* @danielschramm @mvturnho
|
esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||||
esphome/components/mcp3204/* @rsumner
|
esphome/components/mcp3204/* @rsumner
|
||||||
|
esphome/components/mcp4728/* @berfenger
|
||||||
esphome/components/mcp47a1/* @jesserockz
|
esphome/components/mcp47a1/* @jesserockz
|
||||||
|
esphome/components/mcp9600/* @MrEditor97
|
||||||
esphome/components/mcp9808/* @k7hpn
|
esphome/components/mcp9808/* @k7hpn
|
||||||
esphome/components/md5/* @esphome/core
|
esphome/components/md5/* @esphome/core
|
||||||
esphome/components/mdns/* @esphome/core
|
esphome/components/mdns/* @esphome/core
|
||||||
|
esphome/components/media_player/* @jesserockz
|
||||||
|
esphome/components/mics_4514/* @jesserockz
|
||||||
esphome/components/midea/* @dudanov
|
esphome/components/midea/* @dudanov
|
||||||
esphome/components/midea_ir/* @dudanov
|
esphome/components/midea_ir/* @dudanov
|
||||||
esphome/components/mitsubishi/* @RubyBailey
|
esphome/components/mitsubishi/* @RubyBailey
|
||||||
@@ -120,6 +160,10 @@ esphome/components/modbus_controller/select/* @martgras @stegm
|
|||||||
esphome/components/modbus_controller/sensor/* @martgras
|
esphome/components/modbus_controller/sensor/* @martgras
|
||||||
esphome/components/modbus_controller/switch/* @martgras
|
esphome/components/modbus_controller/switch/* @martgras
|
||||||
esphome/components/modbus_controller/text_sensor/* @martgras
|
esphome/components/modbus_controller/text_sensor/* @martgras
|
||||||
|
esphome/components/mopeka_ble/* @spbrogan
|
||||||
|
esphome/components/mopeka_pro_check/* @spbrogan
|
||||||
|
esphome/components/mpl3115a2/* @kbickar
|
||||||
|
esphome/components/mpu6886/* @fabaff
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/nextion/* @senexcrenshaw
|
esphome/components/nextion/* @senexcrenshaw
|
||||||
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
||||||
@@ -130,6 +174,8 @@ esphome/components/nfc/* @jesserockz
|
|||||||
esphome/components/number/* @esphome/core
|
esphome/components/number/* @esphome/core
|
||||||
esphome/components/ota/* @esphome/core
|
esphome/components/ota/* @esphome/core
|
||||||
esphome/components/output/* @esphome/core
|
esphome/components/output/* @esphome/core
|
||||||
|
esphome/components/pca9554/* @hwstar
|
||||||
|
esphome/components/pcf85063/* @brogon
|
||||||
esphome/components/pid/* @OttoWinter
|
esphome/components/pid/* @OttoWinter
|
||||||
esphome/components/pipsolar/* @andreashergert1984
|
esphome/components/pipsolar/* @andreashergert1984
|
||||||
esphome/components/pm1006/* @habbie
|
esphome/components/pm1006/* @habbie
|
||||||
@@ -140,8 +186,9 @@ esphome/components/pn532_spi/* @OttoWinter @jesserockz
|
|||||||
esphome/components/power_supply/* @esphome/core
|
esphome/components/power_supply/* @esphome/core
|
||||||
esphome/components/preferences/* @esphome/core
|
esphome/components/preferences/* @esphome/core
|
||||||
esphome/components/psram/* @esphome/core
|
esphome/components/psram/* @esphome/core
|
||||||
esphome/components/pulse_meter/* @stevebaxter
|
esphome/components/pulse_meter/* @cstaahl @stevebaxter
|
||||||
esphome/components/pvvx_mithermometer/* @pasiz
|
esphome/components/pvvx_mithermometer/* @pasiz
|
||||||
|
esphome/components/qmp6988/* @andrewpc
|
||||||
esphome/components/qr_code/* @wjtje
|
esphome/components/qr_code/* @wjtje
|
||||||
esphome/components/radon_eye_ble/* @jeffeb3
|
esphome/components/radon_eye_ble/* @jeffeb3
|
||||||
esphome/components/radon_eye_rd200/* @jeffeb3
|
esphome/components/radon_eye_rd200/* @jeffeb3
|
||||||
@@ -151,22 +198,38 @@ esphome/components/rc522_spi/* @glmnet
|
|||||||
esphome/components/restart/* @esphome/core
|
esphome/components/restart/* @esphome/core
|
||||||
esphome/components/rf_bridge/* @jesserockz
|
esphome/components/rf_bridge/* @jesserockz
|
||||||
esphome/components/rgbct/* @jesserockz
|
esphome/components/rgbct/* @jesserockz
|
||||||
|
esphome/components/rp2040/* @jesserockz
|
||||||
|
esphome/components/rp2040_pwm/* @jesserockz
|
||||||
esphome/components/rtttl/* @glmnet
|
esphome/components/rtttl/* @glmnet
|
||||||
esphome/components/safe_mode/* @jsuanet @paulmonigatti
|
esphome/components/safe_mode/* @jsuanet @paulmonigatti
|
||||||
esphome/components/scd4x/* @sjtrny
|
esphome/components/scd4x/* @martgras @sjtrny
|
||||||
esphome/components/script/* @esphome/core
|
esphome/components/script/* @esphome/core
|
||||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
|
esphome/components/sdm_meter/* @jesserockz @polyfaces
|
||||||
esphome/components/sdp3x/* @Azimath
|
esphome/components/sdp3x/* @Azimath
|
||||||
esphome/components/selec_meter/* @sourabhjaiswal
|
esphome/components/selec_meter/* @sourabhjaiswal
|
||||||
esphome/components/select/* @esphome/core
|
esphome/components/select/* @esphome/core
|
||||||
|
esphome/components/sen5x/* @martgras
|
||||||
|
esphome/components/sensirion_common/* @martgras
|
||||||
esphome/components/sensor/* @esphome/core
|
esphome/components/sensor/* @esphome/core
|
||||||
esphome/components/sgp40/* @SenexCrenshaw
|
esphome/components/sgp40/* @SenexCrenshaw
|
||||||
|
esphome/components/sgp4x/* @SenexCrenshaw @martgras
|
||||||
|
esphome/components/shelly_dimmer/* @edge90 @rnauber
|
||||||
esphome/components/sht4x/* @sjtrny
|
esphome/components/sht4x/* @sjtrny
|
||||||
esphome/components/shutdown/* @esphome/core @jsuanet
|
esphome/components/shutdown/* @esphome/core @jsuanet
|
||||||
|
esphome/components/sigma_delta_output/* @Cat-Ion
|
||||||
esphome/components/sim800l/* @glmnet
|
esphome/components/sim800l/* @glmnet
|
||||||
|
esphome/components/sm10bit_base/* @Cossid
|
||||||
esphome/components/sm2135/* @BoukeHaarsma23
|
esphome/components/sm2135/* @BoukeHaarsma23
|
||||||
|
esphome/components/sm2235/* @Cossid
|
||||||
|
esphome/components/sm2335/* @Cossid
|
||||||
|
esphome/components/sml/* @alengwenus
|
||||||
|
esphome/components/smt100/* @piechade
|
||||||
|
esphome/components/sn74hc165/* @jesserockz
|
||||||
esphome/components/socket/* @esphome/core
|
esphome/components/socket/* @esphome/core
|
||||||
|
esphome/components/sonoff_d1/* @anatoly-savchenkov
|
||||||
esphome/components/spi/* @esphome/core
|
esphome/components/spi/* @esphome/core
|
||||||
|
esphome/components/sprinkler/* @kbx81
|
||||||
|
esphome/components/sps30/* @martgras
|
||||||
esphome/components/ssd1322_base/* @kbx81
|
esphome/components/ssd1322_base/* @kbx81
|
||||||
esphome/components/ssd1322_spi/* @kbx81
|
esphome/components/ssd1322_spi/* @kbx81
|
||||||
esphome/components/ssd1325_base/* @kbx81
|
esphome/components/ssd1325_base/* @kbx81
|
||||||
@@ -187,11 +250,14 @@ esphome/components/switch/* @esphome/core
|
|||||||
esphome/components/t6615/* @tylermenezes
|
esphome/components/t6615/* @tylermenezes
|
||||||
esphome/components/tca9548a/* @andreashergert1984
|
esphome/components/tca9548a/* @andreashergert1984
|
||||||
esphome/components/tcl112/* @glmnet
|
esphome/components/tcl112/* @glmnet
|
||||||
|
esphome/components/tee501/* @Stock-M
|
||||||
esphome/components/teleinfo/* @0hax
|
esphome/components/teleinfo/* @0hax
|
||||||
esphome/components/thermostat/* @kbx81
|
esphome/components/thermostat/* @kbx81
|
||||||
esphome/components/time/* @OttoWinter
|
esphome/components/time/* @OttoWinter
|
||||||
esphome/components/tlc5947/* @rnauber
|
esphome/components/tlc5947/* @rnauber
|
||||||
|
esphome/components/tm1621/* @Philippe12
|
||||||
esphome/components/tm1637/* @glmnet
|
esphome/components/tm1637/* @glmnet
|
||||||
|
esphome/components/tm1638/* @skykingjwc
|
||||||
esphome/components/tmp102/* @timsavage
|
esphome/components/tmp102/* @timsavage
|
||||||
esphome/components/tmp117/* @Azimath
|
esphome/components/tmp117/* @Azimath
|
||||||
esphome/components/tof10120/* @wstrzalka
|
esphome/components/tof10120/* @wstrzalka
|
||||||
@@ -201,16 +267,25 @@ esphome/components/tsl2591/* @wjcarpenter
|
|||||||
esphome/components/tuya/binary_sensor/* @jesserockz
|
esphome/components/tuya/binary_sensor/* @jesserockz
|
||||||
esphome/components/tuya/climate/* @jesserockz
|
esphome/components/tuya/climate/* @jesserockz
|
||||||
esphome/components/tuya/number/* @frankiboy1
|
esphome/components/tuya/number/* @frankiboy1
|
||||||
|
esphome/components/tuya/select/* @bearpawmaxim
|
||||||
esphome/components/tuya/sensor/* @jesserockz
|
esphome/components/tuya/sensor/* @jesserockz
|
||||||
esphome/components/tuya/switch/* @jesserockz
|
esphome/components/tuya/switch/* @jesserockz
|
||||||
esphome/components/tuya/text_sensor/* @dentra
|
esphome/components/tuya/text_sensor/* @dentra
|
||||||
esphome/components/uart/* @esphome/core
|
esphome/components/uart/* @esphome/core
|
||||||
|
esphome/components/ufire_ec/* @pvizeli
|
||||||
|
esphome/components/ufire_ise/* @pvizeli
|
||||||
esphome/components/ultrasonic/* @OttoWinter
|
esphome/components/ultrasonic/* @OttoWinter
|
||||||
|
esphome/components/vbus/* @ssieb
|
||||||
esphome/components/version/* @esphome/core
|
esphome/components/version/* @esphome/core
|
||||||
esphome/components/wake_on_lan/* @willwill2will54
|
esphome/components/wake_on_lan/* @willwill2will54
|
||||||
esphome/components/web_server_base/* @OttoWinter
|
esphome/components/web_server_base/* @OttoWinter
|
||||||
esphome/components/whirlpool/* @glmnet
|
esphome/components/whirlpool/* @glmnet
|
||||||
|
esphome/components/whynter/* @aeonsablaze
|
||||||
|
esphome/components/wiegand/* @ssieb
|
||||||
|
esphome/components/wl_134/* @hobbypunk90
|
||||||
|
esphome/components/x9c/* @EtienneMD
|
||||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
|
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
|
||||||
esphome/components/xiaomi_mhoc303/* @drug123
|
esphome/components/xiaomi_mhoc303/* @drug123
|
||||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
|
esphome/components/xiaomi_mhoc401/* @vevsvevs
|
||||||
esphome/components/xpt2046/* @numo68
|
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
|
||||||
|
esphome/components/xpt2046/* @nielsnl68 @numo68
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ For a detailed guide, please see https://esphome.io/guides/contributing.html#con
|
|||||||
Things to note when contributing:
|
Things to note when contributing:
|
||||||
|
|
||||||
- Please test your changes :)
|
- Please test your changes :)
|
||||||
- If a new feature is added or an existing user-facing feature is changed, you should also
|
- If a new feature is added or an existing user-facing feature is changed, you should also
|
||||||
update the [docs](https://github.com/esphome/esphome-docs). See [contributing to esphome-docs](https://esphome.io/guides/contributing.html#contributing-to-esphomedocs)
|
update the [docs](https://github.com/esphome/esphome-docs). See [contributing to esphome-docs](https://esphome.io/guides/contributing.html#contributing-to-esphomedocs)
|
||||||
for more information.
|
for more information.
|
||||||
- Please also update the tests in the `tests/` folder. You can do so by just adding a line in one of the YAML files
|
- Please also update the tests in the `tests/` folder. You can do so by just adding a line in one of the YAML files
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
include LICENSE
|
include LICENSE
|
||||||
include README.md
|
include README.md
|
||||||
include requirements.txt
|
include requirements.txt
|
||||||
include esphome/dashboard/templates/*.html
|
recursive-include esphome *.cpp *.h *.tcc *.c
|
||||||
recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE
|
|
||||||
recursive-include esphome *.cpp *.h *.tcc
|
|
||||||
recursive-include esphome *.py.script
|
recursive-include esphome *.py.script
|
||||||
recursive-include esphome LICENSE.txt
|
recursive-include esphome LICENSE.txt
|
||||||
|
|||||||
@@ -5,29 +5,29 @@
|
|||||||
# One of "docker", "hassio"
|
# One of "docker", "hassio"
|
||||||
ARG BASEIMGTYPE=docker
|
ARG BASEIMGTYPE=docker
|
||||||
|
|
||||||
FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64
|
# https://github.com/hassio-addons/addon-debian-base/releases
|
||||||
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64
|
FROM ghcr.io/hassio-addons/debian-base:6.2.0 AS base-hassio
|
||||||
FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7
|
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-amd64
|
FROM debian:bullseye-20221024-slim AS base-docker
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-arm64
|
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-armv7
|
|
||||||
|
|
||||||
# Use TARGETARCH/TARGETVARIANT defined by docker
|
FROM base-${BASEIMGTYPE} AS base
|
||||||
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
|
|
||||||
FROM base-${BASEIMGTYPE}-${TARGETARCH}${TARGETVARIANT} AS base
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
apt-get update \
|
apt-get update \
|
||||||
# Use pinned versions so that we get updates with build caching
|
# Use pinned versions so that we get updates with build caching
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
python3=3.9.2-3 \
|
python3=3.9.2-3 \
|
||||||
python3-pip=20.3.4-4 \
|
python3-pip=20.3.4-4+deb11u1 \
|
||||||
python3-setuptools=52.0.0-4 \
|
python3-setuptools=52.0.0-4 \
|
||||||
python3-pil=8.1.2+dfsg-0.3+deb11u1 \
|
python3-pil=8.1.2+dfsg-0.3+deb11u1 \
|
||||||
python3-cryptography=3.3.2-1 \
|
python3-cryptography=3.3.2-1 \
|
||||||
iputils-ping=3:20210202-1 \
|
iputils-ping=3:20210202-1 \
|
||||||
git=1:2.30.2-1 \
|
git=1:2.30.2-1 \
|
||||||
curl=7.74.0-1.3+deb11u1 \
|
curl=7.74.0-1.3+deb11u5 \
|
||||||
|
openssh-client=1:8.4p1-5+deb11u1 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
@@ -39,29 +39,35 @@ ENV \
|
|||||||
# Store globally installed pio libs in /piolibs
|
# Store globally installed pio libs in /piolibs
|
||||||
PLATFORMIO_GLOBALLIB_DIR=/piolibs
|
PLATFORMIO_GLOBALLIB_DIR=/piolibs
|
||||||
|
|
||||||
|
# Support legacy binaries on Debian multiarch system. There is no "correct" way
|
||||||
|
# to do this, other than using properly built toolchains...
|
||||||
|
# See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian
|
||||||
|
RUN \
|
||||||
|
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||||
|
ln -s /lib/arm-linux-gnueabihf/ld-linux.so.3 /lib/ld-linux.so.3; \
|
||||||
|
fi
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
# Ubuntu python3-pip is missing wheel
|
# Ubuntu python3-pip is missing wheel
|
||||||
pip3 install --no-cache-dir \
|
pip3 install --no-cache-dir \
|
||||||
wheel==0.37.1 \
|
wheel==0.37.1 \
|
||||||
platformio==5.2.5 \
|
platformio==6.1.5 \
|
||||||
# Change some platformio settings
|
# Change some platformio settings
|
||||||
&& platformio settings set enable_telemetry No \
|
&& platformio settings set enable_telemetry No \
|
||||||
&& platformio settings set check_libraries_interval 1000000 \
|
|
||||||
&& platformio settings set check_platformio_interval 1000000 \
|
&& platformio settings set check_platformio_interval 1000000 \
|
||||||
&& platformio settings set check_platforms_interval 1000000 \
|
|
||||||
&& mkdir -p /piolibs
|
&& mkdir -p /piolibs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ======================= docker-type image =======================
|
|
||||||
FROM base AS docker
|
|
||||||
|
|
||||||
# First install requirements to leverage caching when requirements don't change
|
# First install requirements to leverage caching when requirements don't change
|
||||||
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
||||||
RUN \
|
RUN \
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
&& /platformio_install_deps.py /platformio.ini
|
||||||
|
|
||||||
|
|
||||||
|
# ======================= docker-type image =======================
|
||||||
|
FROM base AS docker
|
||||||
|
|
||||||
# Copy esphome and install
|
# Copy esphome and install
|
||||||
COPY . /esphome
|
COPY . /esphome
|
||||||
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
||||||
@@ -93,7 +99,7 @@ RUN \
|
|||||||
apt-get update \
|
apt-get update \
|
||||||
# Use pinned versions so that we get updates with build caching
|
# Use pinned versions so that we get updates with build caching
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
nginx=1.18.0-6.1 \
|
nginx-light=1.18.0-6.1+deb11u3 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
@@ -104,12 +110,6 @@ ARG BUILD_VERSION=dev
|
|||||||
# Copy root filesystem
|
# Copy root filesystem
|
||||||
COPY docker/ha-addon-rootfs/ /
|
COPY docker/ha-addon-rootfs/ /
|
||||||
|
|
||||||
# First install requirements to leverage caching when requirements don't change
|
|
||||||
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
|
||||||
RUN \
|
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
|
||||||
|
|
||||||
# Copy esphome and install
|
# Copy esphome and install
|
||||||
COPY . /esphome
|
COPY . /esphome
|
||||||
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
||||||
@@ -139,7 +139,7 @@ RUN \
|
|||||||
clang-tidy-11=1:11.0.1-2 \
|
clang-tidy-11=1:11.0.1-2 \
|
||||||
patch=2.7.6-7 \
|
patch=2.7.6-7 \
|
||||||
software-properties-common=0.96.20.2-2.1 \
|
software-properties-common=0.96.20.2-2.1 \
|
||||||
nano=5.4-2 \
|
nano=5.4-2+deb11u2 \
|
||||||
build-essential=12.9 \
|
build-essential=12.9 \
|
||||||
python3-dev=3.9.2-3 \
|
python3-dev=3.9.2-3 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
@@ -147,10 +147,8 @@ RUN \
|
|||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
/var/lib/apt/lists/*
|
/var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini /
|
COPY requirements_test.txt /
|
||||||
RUN \
|
RUN pip3 install --no-cache-dir -r /requirements_test.txt
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \
|
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
|
||||||
|
|
||||||
VOLUME ["/esphome"]
|
VOLUME ["/esphome"]
|
||||||
WORKDIR /esphome
|
WORKDIR /esphome
|
||||||
|
|||||||
@@ -8,32 +8,49 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
CHANNEL_DEV = 'dev'
|
CHANNEL_DEV = "dev"
|
||||||
CHANNEL_BETA = 'beta'
|
CHANNEL_BETA = "beta"
|
||||||
CHANNEL_RELEASE = 'release'
|
CHANNEL_RELEASE = "release"
|
||||||
CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
|
CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
|
||||||
|
|
||||||
ARCH_AMD64 = 'amd64'
|
ARCH_AMD64 = "amd64"
|
||||||
ARCH_ARMV7 = 'armv7'
|
ARCH_ARMV7 = "armv7"
|
||||||
ARCH_AARCH64 = 'aarch64'
|
ARCH_AARCH64 = "aarch64"
|
||||||
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
|
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
|
||||||
|
|
||||||
TYPE_DOCKER = 'docker'
|
TYPE_DOCKER = "docker"
|
||||||
TYPE_HA_ADDON = 'ha-addon'
|
TYPE_HA_ADDON = "ha-addon"
|
||||||
TYPE_LINT = 'lint'
|
TYPE_LINT = "lint"
|
||||||
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
|
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--tag", type=str, required=True, help="The main docker tag to push to. If a version number also adds latest and/or beta tag")
|
parser.add_argument(
|
||||||
parser.add_argument("--arch", choices=ARCHS, required=False, help="The architecture to build for")
|
"--tag",
|
||||||
parser.add_argument("--build-type", choices=TYPES, required=True, help="The type of build to run")
|
type=str,
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Don't run any commands, just print them")
|
required=True,
|
||||||
subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
|
help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--arch", choices=ARCHS, required=False, help="The architecture to build for"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--build-type", choices=TYPES, required=True, help="The type of build to run"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dry-run", action="store_true", help="Don't run any commands, just print them"
|
||||||
|
)
|
||||||
|
subparsers = parser.add_subparsers(
|
||||||
|
help="Action to perform", dest="command", required=True
|
||||||
|
)
|
||||||
build_parser = subparsers.add_parser("build", help="Build the image")
|
build_parser = subparsers.add_parser("build", help="Build the image")
|
||||||
build_parser.add_argument("--push", help="Also push the images", action="store_true")
|
build_parser.add_argument("--push", help="Also push the images", action="store_true")
|
||||||
build_parser.add_argument("--load", help="Load the docker image locally", action="store_true")
|
build_parser.add_argument(
|
||||||
manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
|
"--load", help="Load the docker image locally", action="store_true"
|
||||||
|
)
|
||||||
|
manifest_parser = subparsers.add_parser(
|
||||||
|
"manifest", help="Create a manifest from already pushed images"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -49,7 +66,7 @@ class DockerParams:
|
|||||||
prefix = {
|
prefix = {
|
||||||
TYPE_DOCKER: "esphome/esphome",
|
TYPE_DOCKER: "esphome/esphome",
|
||||||
TYPE_HA_ADDON: "esphome/esphome-hassio",
|
TYPE_HA_ADDON: "esphome/esphome-hassio",
|
||||||
TYPE_LINT: "esphome/esphome-lint"
|
TYPE_LINT: "esphome/esphome-lint",
|
||||||
}[build_type]
|
}[build_type]
|
||||||
build_to = f"{prefix}-{arch}"
|
build_to = f"{prefix}-{arch}"
|
||||||
baseimgtype = {
|
baseimgtype = {
|
||||||
@@ -88,10 +105,12 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# detect channel from tag
|
# detect channel from tag
|
||||||
match = re.match(r'^\d+\.\d+(?:\.\d+)?(b\d+)?$', args.tag)
|
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
|
||||||
|
major_minor_version = None
|
||||||
if match is None:
|
if match is None:
|
||||||
channel = CHANNEL_DEV
|
channel = CHANNEL_DEV
|
||||||
elif match.group(1) is None:
|
elif match.group(2) is None:
|
||||||
|
major_minor_version = match.group(1)
|
||||||
channel = CHANNEL_RELEASE
|
channel = CHANNEL_RELEASE
|
||||||
else:
|
else:
|
||||||
channel = CHANNEL_BETA
|
channel = CHANNEL_BETA
|
||||||
@@ -106,6 +125,11 @@ def main():
|
|||||||
tags_to_push.append("beta")
|
tags_to_push.append("beta")
|
||||||
tags_to_push.append("latest")
|
tags_to_push.append("latest")
|
||||||
|
|
||||||
|
# Compatibility with HA tags
|
||||||
|
if major_minor_version:
|
||||||
|
tags_to_push.append("stable")
|
||||||
|
tags_to_push.append(major_minor_version)
|
||||||
|
|
||||||
if args.command == "build":
|
if args.command == "build":
|
||||||
# 1. pull cache image
|
# 1. pull cache image
|
||||||
params = DockerParams.for_type_arch(args.build_type, args.arch)
|
params = DockerParams.for_type_arch(args.build_type, args.arch)
|
||||||
@@ -121,13 +145,21 @@ def main():
|
|||||||
|
|
||||||
# 3. build
|
# 3. build
|
||||||
cmd = [
|
cmd = [
|
||||||
"docker", "buildx", "build",
|
"docker",
|
||||||
"--build-arg", f"BASEIMGTYPE={params.baseimgtype}",
|
"buildx",
|
||||||
"--build-arg", f"BUILD_VERSION={args.tag}",
|
"build",
|
||||||
"--cache-from", f"type=registry,ref={cache_img}",
|
"--build-arg",
|
||||||
"--file", "docker/Dockerfile",
|
f"BASEIMGTYPE={params.baseimgtype}",
|
||||||
"--platform", params.platform,
|
"--build-arg",
|
||||||
"--target", params.target,
|
f"BUILD_VERSION={args.tag}",
|
||||||
|
"--cache-from",
|
||||||
|
f"type=registry,ref={cache_img}",
|
||||||
|
"--file",
|
||||||
|
"docker/Dockerfile",
|
||||||
|
"--platform",
|
||||||
|
params.platform,
|
||||||
|
"--target",
|
||||||
|
params.target,
|
||||||
]
|
]
|
||||||
for img in imgs:
|
for img in imgs:
|
||||||
cmd += ["--tag", img]
|
cmd += ["--tag", img]
|
||||||
@@ -153,9 +185,7 @@ def main():
|
|||||||
run_command(*cmd)
|
run_command(*cmd)
|
||||||
# 2. Push manifests
|
# 2. Push manifests
|
||||||
for target in targets:
|
for target in targets:
|
||||||
run_command(
|
run_command("docker", "manifest", "push", target)
|
||||||
"docker", "manifest", "push", target
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
68
docker/generate_tags.py
Executable file
68
docker/generate_tags.py
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
|
CHANNEL_DEV = "dev"
|
||||||
|
CHANNEL_BETA = "beta"
|
||||||
|
CHANNEL_RELEASE = "release"
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--tag",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--suffix",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="The suffix of the tag.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# detect channel from tag
|
||||||
|
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
|
||||||
|
major_minor_version = None
|
||||||
|
if match is None:
|
||||||
|
channel = CHANNEL_DEV
|
||||||
|
elif match.group(2) is None:
|
||||||
|
major_minor_version = match.group(1)
|
||||||
|
channel = CHANNEL_RELEASE
|
||||||
|
else:
|
||||||
|
channel = CHANNEL_BETA
|
||||||
|
|
||||||
|
tags_to_push = [args.tag]
|
||||||
|
if channel == CHANNEL_DEV:
|
||||||
|
tags_to_push.append("dev")
|
||||||
|
elif channel == CHANNEL_BETA:
|
||||||
|
tags_to_push.append("beta")
|
||||||
|
elif channel == CHANNEL_RELEASE:
|
||||||
|
# Additionally push to beta
|
||||||
|
tags_to_push.append("beta")
|
||||||
|
tags_to_push.append("latest")
|
||||||
|
|
||||||
|
if major_minor_version:
|
||||||
|
tags_to_push.append("stable")
|
||||||
|
tags_to_push.append(major_minor_version)
|
||||||
|
|
||||||
|
suffix = f"-{args.suffix}" if args.suffix else ""
|
||||||
|
|
||||||
|
with open(os.environ["GITHUB_OUTPUT"], "w") as f:
|
||||||
|
print(f"channel={channel}", file=f)
|
||||||
|
print(f"image=esphome/esphome{suffix}", file=f)
|
||||||
|
full_tags = []
|
||||||
|
|
||||||
|
for tag in tags_to_push:
|
||||||
|
full_tags += [f"ghcr.io/esphome/esphome{suffix}:{tag}"]
|
||||||
|
full_tags += [f"esphome/esphome{suffix}:{tag}"]
|
||||||
|
print(f"tags={','.join(full_tags)}", file=f)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# This files check if all user configuration requirements are met
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
# Check SSL requirements, if enabled
|
|
||||||
if bashio::config.true 'ssl'; then
|
|
||||||
if ! bashio::config.has_value 'certfile'; then
|
|
||||||
bashio::log.fatal 'SSL is enabled, but no certfile was specified.'
|
|
||||||
bashio::exit.nok
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! bashio::config.has_value 'keyfile'; then
|
|
||||||
bashio::log.fatal 'SSL is enabled, but no keyfile was specified'
|
|
||||||
bashio::exit.nok
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
certfile="/ssl/$(bashio::config 'certfile')"
|
|
||||||
keyfile="/ssl/$(bashio::config 'keyfile')"
|
|
||||||
|
|
||||||
if ! bashio::fs.file_exists "${certfile}"; then
|
|
||||||
if ! bashio::fs.file_exists "${keyfile}"; then
|
|
||||||
# Both files are missing, let's print a friendlier error message
|
|
||||||
bashio::log.fatal 'You enabled encrypted connections using the "ssl": true option.'
|
|
||||||
bashio::log.fatal "However, the SSL files '${certfile}' and '${keyfile}'"
|
|
||||||
bashio::log.fatal "were not found. If you're using Hass.io on your local network and don't want"
|
|
||||||
bashio::log.fatal 'to encrypt connections to the ESPHome dashboard, you can manually disable'
|
|
||||||
bashio::log.fatal 'SSL by setting "ssl" to false."'
|
|
||||||
bashio::exit.nok
|
|
||||||
fi
|
|
||||||
bashio::log.fatal "The configured certfile '${certfile}' was not found."
|
|
||||||
bashio::exit.nok
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! bashio::fs.file_exists "/ssl/$(bashio::config 'keyfile')"; then
|
|
||||||
bashio::log.fatal "The configured keyfile '${keyfile}' was not found."
|
|
||||||
bashio::exit.nok
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Configures NGINX for use with ESPHome
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
declare certfile
|
|
||||||
declare keyfile
|
|
||||||
declare direct_port
|
|
||||||
declare ingress_interface
|
|
||||||
declare ingress_port
|
|
||||||
|
|
||||||
mkdir -p /var/log/nginx
|
|
||||||
|
|
||||||
direct_port=$(bashio::addon.port 6052)
|
|
||||||
if bashio::var.has_value "${direct_port}"; then
|
|
||||||
if bashio::config.true 'ssl'; then
|
|
||||||
certfile=$(bashio::config 'certfile')
|
|
||||||
keyfile=$(bashio::config 'keyfile')
|
|
||||||
|
|
||||||
mv /etc/nginx/servers/direct-ssl.disabled /etc/nginx/servers/direct.conf
|
|
||||||
sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/servers/direct.conf
|
|
||||||
sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/servers/direct.conf
|
|
||||||
else
|
|
||||||
mv /etc/nginx/servers/direct.disabled /etc/nginx/servers/direct.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i "s/%%port%%/${direct_port}/g" /etc/nginx/servers/direct.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
ingress_port=$(bashio::addon.ingress_port)
|
|
||||||
ingress_interface=$(bashio::addon.ip_address)
|
|
||||||
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
|
|
||||||
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# This files creates all directories used by esphome
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
pio_cache_base=/data/cache/platformio
|
|
||||||
|
|
||||||
mkdir -p "${pio_cache_base}"
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_ignore_client_abort off;
|
proxy_ignore_client_abort off;
|
||||||
proxy_read_timeout 86400s;
|
proxy_read_timeout 86400s;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_send_timeout 86400s;
|
proxy_send_timeout 86400s;
|
||||||
proxy_max_temp_file_size 0;
|
proxy_max_temp_file_size 0;
|
||||||
|
|
||||||
proxy_set_header Accept-Encoding "";
|
proxy_set_header Accept-Encoding "";
|
||||||
proxy_set_header Connection $connection_upgrade;
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
root /dev/null;
|
root /dev/null;
|
||||||
server_name $hostname;
|
server_name $hostname;
|
||||||
|
|
||||||
|
client_max_body_size 512m;
|
||||||
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
add_header X-Content-Type-Options nosniff;
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
ssl_protocols TLSv1.2;
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers off;
|
||||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
ssl_ecdh_curve secp384r1;
|
|
||||||
ssl_session_timeout 10m;
|
ssl_session_timeout 10m;
|
||||||
ssl_session_cache shared:SSL:10m;
|
ssl_session_cache shared:SSL:10m;
|
||||||
ssl_session_tickets off;
|
ssl_session_tickets off;
|
||||||
|
|||||||
3
docker/ha-addon-rootfs/etc/nginx/includes/upstream.conf
Normal file
3
docker/ha-addon-rootfs/etc/nginx/includes/upstream.conf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
upstream esphome {
|
||||||
|
server unix:/var/run/esphome.sock;
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ daemon off;
|
|||||||
user root;
|
user root;
|
||||||
pid /var/run/nginx.pid;
|
pid /var/run/nginx.pid;
|
||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
# Hass.io addon log
|
|
||||||
error_log /proc/1/fd/1 error;
|
error_log /proc/1/fd/1 error;
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
@@ -10,24 +9,22 @@ events {
|
|||||||
|
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/includes/mime.types;
|
include /etc/nginx/includes/mime.types;
|
||||||
access_log stdout;
|
|
||||||
default_type application/octet-stream;
|
access_log off;
|
||||||
gzip on;
|
default_type application/octet-stream;
|
||||||
keepalive_timeout 65;
|
gzip on;
|
||||||
sendfile on;
|
keepalive_timeout 65;
|
||||||
server_tokens off;
|
sendfile on;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
tcp_nodelay on;
|
||||||
|
tcp_nopush on;
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
'' close;
|
'' close;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Use Hass.io supervisor as resolver
|
include /etc/nginx/includes/upstream.conf;
|
||||||
resolver 172.30.32.2;
|
|
||||||
|
|
||||||
upstream esphome {
|
|
||||||
server unix:/var/run/esphome.sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
include /etc/nginx/servers/*.conf;
|
include /etc/nginx/servers/*.conf;
|
||||||
}
|
}
|
||||||
|
|||||||
1
docker/ha-addon-rootfs/etc/nginx/servers/.gitkeep
Normal file
1
docker/ha-addon-rootfs/etc/nginx/servers/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
server {
|
|
||||||
listen %%port%% default_server;
|
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
|
||||||
include /etc/nginx/includes/proxy_params.conf;
|
|
||||||
# Clear Hass.io Ingress header
|
|
||||||
proxy_set_header X-HA-Ingress "";
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://esphome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
server {
|
server {
|
||||||
listen %%port%% default_server ssl http2;
|
{{ if not .ssl }}
|
||||||
|
listen 6052 default_server;
|
||||||
|
{{ else }}
|
||||||
|
listen 6052 default_server ssl http2;
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
include /etc/nginx/includes/server_params.conf;
|
||||||
include /etc/nginx/includes/proxy_params.conf;
|
include /etc/nginx/includes/proxy_params.conf;
|
||||||
|
|
||||||
|
{{ if .ssl }}
|
||||||
include /etc/nginx/includes/ssl_params.conf;
|
include /etc/nginx/includes/ssl_params.conf;
|
||||||
|
|
||||||
ssl on;
|
ssl_certificate /ssl/{{ .certfile }};
|
||||||
ssl_certificate /ssl/%%certfile%%;
|
ssl_certificate_key /ssl/{{ .keyfile }};
|
||||||
ssl_certificate_key /ssl/%%keyfile%%;
|
|
||||||
|
|
||||||
# Clear Hass.io Ingress header
|
|
||||||
proxy_set_header X-HA-Ingress "";
|
|
||||||
|
|
||||||
# Redirect http requests to https on the same port.
|
# Redirect http requests to https on the same port.
|
||||||
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
|
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
|
||||||
error_page 497 https://$http_host$request_uri;
|
error_page 497 https://$http_host$request_uri;
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
# Clear Home Assistant Ingress header
|
||||||
|
proxy_set_header X-HA-Ingress "";
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://esphome;
|
proxy_pass http://esphome;
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
server {
|
server {
|
||||||
listen %%interface%%:%%port%% default_server;
|
listen 127.0.0.1:{{ .port }} default_server;
|
||||||
|
listen {{ .interface }}:{{ .port }} default_server;
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
include /etc/nginx/includes/server_params.conf;
|
||||||
include /etc/nginx/includes/proxy_params.conf;
|
include /etc/nginx/includes/proxy_params.conf;
|
||||||
|
|
||||||
# Set Home Assistant Ingress header
|
# Set Home Assistant Ingress header
|
||||||
proxy_set_header X-HA-Ingress "YES";
|
proxy_set_header X-HA-Ingress "YES";
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
# Only allow from Hass.io supervisor
|
|
||||||
allow 172.30.32.2;
|
allow 172.30.32.2;
|
||||||
|
allow 127.0.0.1;
|
||||||
deny all;
|
deny all;
|
||||||
|
|
||||||
proxy_pass http://esphome;
|
proxy_pass http://esphome;
|
||||||
32
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/discovery/run
Executable file
32
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/discovery/run
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/command/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
|
# ==============================================================================
|
||||||
|
# Home Assistant Add-on: ESPHome
|
||||||
|
# Sends discovery information to Home Assistant.
|
||||||
|
# ==============================================================================
|
||||||
|
declare config
|
||||||
|
declare port
|
||||||
|
|
||||||
|
# We only disable it when disabled explicitly
|
||||||
|
if bashio::config.false 'home_assistant_dashboard_integration';
|
||||||
|
then
|
||||||
|
bashio::log.info "Home Assistant discovery is disabled for this add-on."
|
||||||
|
bashio::exit.ok
|
||||||
|
fi
|
||||||
|
|
||||||
|
port=$(bashio::addon.ingress_port)
|
||||||
|
|
||||||
|
# Wait for NGINX to become available
|
||||||
|
bashio::net.wait_for "${port}" "127.0.0.1" 300
|
||||||
|
|
||||||
|
config=$(\
|
||||||
|
bashio::var.json \
|
||||||
|
host "127.0.0.1" \
|
||||||
|
port "^${port}" \
|
||||||
|
)
|
||||||
|
|
||||||
|
if bashio::discovery "esphome" "${config}" > /dev/null; then
|
||||||
|
bashio::log.info "Successfully send discovery information to Home Assistant."
|
||||||
|
else
|
||||||
|
bashio::log.error "Discovery message to Home Assistant failed!"
|
||||||
|
fi
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
oneshot
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/etc/s6-overlay/s6-rc.d/discovery/run
|
||||||
26
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/finish
Executable file
26
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/finish
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/command/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
|
# ==============================================================================
|
||||||
|
# Home Assistant Community Add-on: ESPHome
|
||||||
|
# Take down the S6 supervision tree when ESPHome dashboard fails
|
||||||
|
# ==============================================================================
|
||||||
|
declare exit_code
|
||||||
|
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
|
||||||
|
readonly exit_code_service="${1}"
|
||||||
|
readonly exit_code_signal="${2}"
|
||||||
|
|
||||||
|
bashio::log.info \
|
||||||
|
"Service ESPHome dashboard exited with code ${exit_code_service}" \
|
||||||
|
"(by signal ${exit_code_signal})"
|
||||||
|
|
||||||
|
if [[ "${exit_code_service}" -eq 256 ]]; then
|
||||||
|
if [[ "${exit_code_container}" -eq 0 ]]; then
|
||||||
|
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
|
||||||
|
fi
|
||||||
|
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
|
||||||
|
elif [[ "${exit_code_service}" -ne 0 ]]; then
|
||||||
|
if [[ "${exit_code_container}" -eq 0 ]]; then
|
||||||
|
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
|
||||||
|
fi
|
||||||
|
exec /run/s6/basedir/bin/halt
|
||||||
|
fi
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
#!/command/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Community Hass.io Add-ons: ESPHome
|
# Community Hass.io Add-ons: ESPHome
|
||||||
# Runs the ESPHome dashboard
|
# Runs the ESPHome dashboard
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
readonly pio_cache_base=/data/cache/platformio
|
||||||
|
|
||||||
export ESPHOME_IS_HA_ADDON=true
|
export ESPHOME_IS_HA_ADDON=true
|
||||||
|
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
|
||||||
|
|
||||||
|
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
|
||||||
|
# setting `core_dir` would therefore prevent pio from accessing
|
||||||
|
export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
|
||||||
|
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
|
||||||
|
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
|
||||||
|
|
||||||
if bashio::config.true 'leave_front_door_open'; then
|
if bashio::config.true 'leave_front_door_open'; then
|
||||||
export DISABLE_HA_AUTHENTICATION=true
|
export DISABLE_HA_AUTHENTICATION=true
|
||||||
@@ -22,14 +31,15 @@ if bashio::config.has_value 'relative_url'; then
|
|||||||
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
|
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pio_cache_base=/data/cache/platformio
|
if bashio::config.has_value 'default_compile_process_limit'; then
|
||||||
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
|
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit')
|
||||||
# setting `core_dir` would therefore prevent pio from accessing
|
else
|
||||||
export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
|
if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then
|
||||||
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
|
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1;
|
||||||
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
|
mkdir -p "${pio_cache_base}"
|
||||||
|
|
||||||
bashio::log.info "Starting ESPHome dashboard..."
|
bashio::log.info "Starting ESPHome dashboard..."
|
||||||
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
|
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
longrun
|
||||||
27
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
Executable file
27
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/command/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
|
# ==============================================================================
|
||||||
|
# Community Hass.io Add-ons: ESPHome
|
||||||
|
# Configures NGINX for use with ESPHome
|
||||||
|
# ==============================================================================
|
||||||
|
mkdir -p /var/log/nginx
|
||||||
|
|
||||||
|
# Generate Ingress configuration
|
||||||
|
bashio::var.json \
|
||||||
|
interface "$(bashio::addon.ip_address)" \
|
||||||
|
port "^$(bashio::addon.ingress_port)" \
|
||||||
|
| tempio \
|
||||||
|
-template /etc/nginx/templates/ingress.gtpl \
|
||||||
|
-out /etc/nginx/servers/ingress.conf
|
||||||
|
|
||||||
|
# Generate direct access configuration, if enabled.
|
||||||
|
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
|
||||||
|
bashio::config.require.ssl
|
||||||
|
bashio::var.json \
|
||||||
|
certfile "$(bashio::config 'certfile')" \
|
||||||
|
keyfile "$(bashio::config 'keyfile')" \
|
||||||
|
ssl "^$(bashio::config 'ssl')" \
|
||||||
|
| tempio \
|
||||||
|
-template /etc/nginx/templates/direct.gtpl \
|
||||||
|
-out /etc/nginx/servers/direct.conf
|
||||||
|
fi
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
oneshot
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/etc/s6-overlay/s6-rc.d/init-nginx/run
|
||||||
25
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/finish
Executable file
25
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/finish
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/command/with-contenv bashio
|
||||||
|
# ==============================================================================
|
||||||
|
# Community Hass.io Add-ons: ESPHome
|
||||||
|
# Take down the S6 supervision tree when NGINX fails
|
||||||
|
# ==============================================================================
|
||||||
|
declare exit_code
|
||||||
|
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
|
||||||
|
readonly exit_code_service="${1}"
|
||||||
|
readonly exit_code_signal="${2}"
|
||||||
|
|
||||||
|
bashio::log.info \
|
||||||
|
"Service NGINX exited with code ${exit_code_service}" \
|
||||||
|
"(by signal ${exit_code_signal})"
|
||||||
|
|
||||||
|
if [[ "${exit_code_service}" -eq 256 ]]; then
|
||||||
|
if [[ "${exit_code_container}" -eq 0 ]]; then
|
||||||
|
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
|
||||||
|
fi
|
||||||
|
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
|
||||||
|
elif [[ "${exit_code_service}" -ne 0 ]]; then
|
||||||
|
if [[ "${exit_code_container}" -eq 0 ]]; then
|
||||||
|
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
|
||||||
|
fi
|
||||||
|
exec /run/s6/basedir/bin/halt
|
||||||
|
fi
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
#!/command/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Community Hass.io Add-ons: ESPHome
|
# Community Hass.io Add-ons: ESPHome
|
||||||
# Runs the NGINX proxy
|
# Runs the NGINX proxy
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
bashio::log.info "Waiting for dashboard to come up..."
|
bashio::log.info "Waiting for ESPHome dashboard to come up..."
|
||||||
|
|
||||||
while [[ ! -S /var/run/esphome.sock ]]; do
|
while [[ ! -S /var/run/esphome.sock ]]; do
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
1
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/type
Normal file
1
docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/type
Normal file
@@ -0,0 +1 @@
|
|||||||
|
longrun
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/execlineb -S0
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Take down the S6 supervision tree when ESPHome fails
|
|
||||||
# ==============================================================================
|
|
||||||
if -n { s6-test $# -ne 0 }
|
|
||||||
if -n { s6-test ${1} -eq 256 }
|
|
||||||
|
|
||||||
s6-svscanctl -t /var/run/s6/services
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/execlineb -S0
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Take down the S6 supervision tree when NGINX fails
|
|
||||||
# ==============================================================================
|
|
||||||
if -n { s6-test $# -ne 0 }
|
|
||||||
if -n { s6-test ${1} -eq 256 }
|
|
||||||
|
|
||||||
s6-svscanctl -t /var/run/s6/services
|
|
||||||
@@ -2,22 +2,30 @@ import argparse
|
|||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from esphome import const, writer, yaml_util
|
from esphome import const, writer, yaml_util
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.config import iter_components, read_config, strip_default_ids
|
from esphome.config import iter_components, read_config, strip_default_ids
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
ALLOWED_NAME_CHARS,
|
||||||
CONF_BAUD_RATE,
|
CONF_BAUD_RATE,
|
||||||
CONF_BROKER,
|
CONF_BROKER,
|
||||||
CONF_DEASSERT_RTS_DTR,
|
CONF_DEASSERT_RTS_DTR,
|
||||||
CONF_LOGGER,
|
CONF_LOGGER,
|
||||||
|
CONF_NAME,
|
||||||
CONF_OTA,
|
CONF_OTA,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
CONF_ESPHOME,
|
CONF_ESPHOME,
|
||||||
CONF_PLATFORMIO_OPTIONS,
|
CONF_PLATFORMIO_OPTIONS,
|
||||||
|
CONF_SUBSTITUTIONS,
|
||||||
|
PLATFORM_ESP32,
|
||||||
|
PLATFORM_ESP8266,
|
||||||
|
PLATFORM_RP2040,
|
||||||
SECRETS_FILES,
|
SECRETS_FILES,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, EsphomeError, coroutine
|
from esphome.core import CORE, EsphomeError, coroutine
|
||||||
@@ -97,11 +105,11 @@ def run_miniterm(config, port):
|
|||||||
|
|
||||||
if CONF_LOGGER not in config:
|
if CONF_LOGGER not in config:
|
||||||
_LOGGER.info("Logger is not enabled. Not starting UART logs.")
|
_LOGGER.info("Logger is not enabled. Not starting UART logs.")
|
||||||
return
|
return 1
|
||||||
baud_rate = config["logger"][CONF_BAUD_RATE]
|
baud_rate = config["logger"][CONF_BAUD_RATE]
|
||||||
if baud_rate == 0:
|
if baud_rate == 0:
|
||||||
_LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.")
|
_LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.")
|
||||||
return
|
return 1
|
||||||
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
|
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
|
||||||
|
|
||||||
backtrace_state = False
|
backtrace_state = False
|
||||||
@@ -115,25 +123,34 @@ def run_miniterm(config, port):
|
|||||||
ser.dtr = False
|
ser.dtr = False
|
||||||
ser.rts = False
|
ser.rts = False
|
||||||
|
|
||||||
with ser:
|
tries = 0
|
||||||
while True:
|
while tries < 5:
|
||||||
try:
|
try:
|
||||||
raw = ser.readline()
|
with ser:
|
||||||
except serial.SerialException:
|
while True:
|
||||||
_LOGGER.error("Serial port closed!")
|
try:
|
||||||
return
|
raw = ser.readline()
|
||||||
line = (
|
except serial.SerialException:
|
||||||
raw.replace(b"\r", b"")
|
_LOGGER.error("Serial port closed!")
|
||||||
.replace(b"\n", b"")
|
return 0
|
||||||
.decode("utf8", "backslashreplace")
|
line = (
|
||||||
)
|
raw.replace(b"\r", b"")
|
||||||
time = datetime.now().time().strftime("[%H:%M:%S]")
|
.replace(b"\n", b"")
|
||||||
message = time + line
|
.decode("utf8", "backslashreplace")
|
||||||
safe_print(message)
|
)
|
||||||
|
time_str = datetime.now().time().strftime("[%H:%M:%S]")
|
||||||
|
message = time_str + line
|
||||||
|
safe_print(message)
|
||||||
|
|
||||||
backtrace_state = platformio_api.process_stacktrace(
|
backtrace_state = platformio_api.process_stacktrace(
|
||||||
config, line, backtrace_state=backtrace_state
|
config, line, backtrace_state=backtrace_state
|
||||||
)
|
)
|
||||||
|
except serial.SerialException:
|
||||||
|
tries += 1
|
||||||
|
time.sleep(1)
|
||||||
|
if tries >= 5:
|
||||||
|
_LOGGER.error("Could not connect to serial port %s", port)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def wrap_to_code(name, comp):
|
def wrap_to_code(name, comp):
|
||||||
@@ -237,8 +254,7 @@ def upload_using_esptool(config, port):
|
|||||||
if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
|
if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
|
||||||
import esptool
|
import esptool
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
return run_external_command(esptool.main, *cmd) # pylint: disable=no-member
|
||||||
return run_external_command(esptool._main, *cmd)
|
|
||||||
|
|
||||||
return run_external_process(*cmd)
|
return run_external_process(*cmd)
|
||||||
|
|
||||||
@@ -254,9 +270,21 @@ def upload_using_esptool(config, port):
|
|||||||
|
|
||||||
|
|
||||||
def upload_program(config, args, host):
|
def upload_program(config, args, host):
|
||||||
# if upload is to a serial port use platformio, otherwise assume ota
|
|
||||||
if get_port_type(host) == "SERIAL":
|
if get_port_type(host) == "SERIAL":
|
||||||
return upload_using_esptool(config, host)
|
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
|
||||||
|
return upload_using_esptool(config, host)
|
||||||
|
|
||||||
|
if CORE.target_platform in (PLATFORM_RP2040):
|
||||||
|
from esphome import platformio_api
|
||||||
|
|
||||||
|
upload_args = ["-t", "upload"]
|
||||||
|
if args.device is not None:
|
||||||
|
upload_args += ["--upload-port", args.device]
|
||||||
|
return platformio_api.run_platformio_cli_run(
|
||||||
|
config, CORE.verbose, *upload_args
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1 # Unknown target platform
|
||||||
|
|
||||||
from esphome import espota2
|
from esphome import espota2
|
||||||
|
|
||||||
@@ -269,6 +297,8 @@ def upload_program(config, args, host):
|
|||||||
ota_conf = config[CONF_OTA]
|
ota_conf = config[CONF_OTA]
|
||||||
remote_port = ota_conf[CONF_PORT]
|
remote_port = ota_conf[CONF_PORT]
|
||||||
password = ota_conf.get(CONF_PASSWORD, "")
|
password = ota_conf.get(CONF_PASSWORD, "")
|
||||||
|
if getattr(args, "file", None) is not None:
|
||||||
|
return espota2.run_ota(host, remote_port, password, args.file)
|
||||||
return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
|
return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
|
||||||
|
|
||||||
|
|
||||||
@@ -276,8 +306,7 @@ def show_logs(config, args, port):
|
|||||||
if "logger" not in config:
|
if "logger" not in config:
|
||||||
raise EsphomeError("Logger is not configured!")
|
raise EsphomeError("Logger is not configured!")
|
||||||
if get_port_type(port) == "SERIAL":
|
if get_port_type(port) == "SERIAL":
|
||||||
run_miniterm(config, port)
|
return run_miniterm(config, port)
|
||||||
return 0
|
|
||||||
if get_port_type(port) == "NETWORK" and "api" in config:
|
if get_port_type(port) == "NETWORK" and "api" in config:
|
||||||
from esphome.components.api.client import run_logs
|
from esphome.components.api.client import run_logs
|
||||||
|
|
||||||
@@ -310,7 +339,7 @@ def command_config(args, config):
|
|||||||
_LOGGER.info("Configuration is valid!")
|
_LOGGER.info("Configuration is valid!")
|
||||||
if not CORE.verbose:
|
if not CORE.verbose:
|
||||||
config = strip_default_ids(config)
|
config = strip_default_ids(config)
|
||||||
safe_print(yaml_util.dump(config))
|
safe_print(yaml_util.dump(config, args.show_secrets))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -481,6 +510,98 @@ def command_idedata(args, config):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def command_rename(args, config):
|
||||||
|
for c in args.name:
|
||||||
|
if c not in ALLOWED_NAME_CHARS:
|
||||||
|
print(
|
||||||
|
color(
|
||||||
|
Fore.BOLD_RED,
|
||||||
|
f"'{c}' is an invalid character for names. Valid characters are: "
|
||||||
|
f"{ALLOWED_NAME_CHARS} (lowercase, no spaces)",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
# Load existing yaml file
|
||||||
|
with open(CORE.config_path, mode="r+", encoding="utf-8") as raw_file:
|
||||||
|
raw_contents = raw_file.read()
|
||||||
|
|
||||||
|
yaml = yaml_util.load_yaml(CORE.config_path)
|
||||||
|
if CONF_ESPHOME not in yaml or CONF_NAME not in yaml[CONF_ESPHOME]:
|
||||||
|
print(
|
||||||
|
color(Fore.BOLD_RED, "Complex YAML files cannot be automatically renamed.")
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
old_name = yaml[CONF_ESPHOME][CONF_NAME]
|
||||||
|
match = re.match(r"^\$\{?([a-zA-Z0-9_]+)\}?$", old_name)
|
||||||
|
if match is None:
|
||||||
|
new_raw = re.sub(
|
||||||
|
rf"name:\s+[\"']?{old_name}[\"']?",
|
||||||
|
f'name: "{args.name}"',
|
||||||
|
raw_contents,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
old_name = yaml[CONF_SUBSTITUTIONS][match.group(1)]
|
||||||
|
if (
|
||||||
|
len(
|
||||||
|
re.findall(
|
||||||
|
rf"^\s+{match.group(1)}:\s+[\"']?{old_name}[\"']?",
|
||||||
|
raw_contents,
|
||||||
|
flags=re.MULTILINE,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
> 1
|
||||||
|
):
|
||||||
|
print(color(Fore.BOLD_RED, "Too many matches in YAML to safely rename"))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
new_raw = re.sub(
|
||||||
|
rf"^(\s+{match.group(1)}):\s+[\"']?{old_name}[\"']?",
|
||||||
|
f'\\1: "{args.name}"',
|
||||||
|
raw_contents,
|
||||||
|
flags=re.MULTILINE,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_path = os.path.join(CORE.config_dir, args.name + ".yaml")
|
||||||
|
print(
|
||||||
|
f"Updating {color(Fore.CYAN, CORE.config_path)} to {color(Fore.CYAN, new_path)}"
|
||||||
|
)
|
||||||
|
print()
|
||||||
|
|
||||||
|
with open(new_path, mode="w", encoding="utf-8") as new_file:
|
||||||
|
new_file.write(new_raw)
|
||||||
|
|
||||||
|
rc = run_external_process("esphome", "config", new_path)
|
||||||
|
if rc != 0:
|
||||||
|
print(color(Fore.BOLD_RED, "Rename failed. Reverting changes."))
|
||||||
|
os.remove(new_path)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
cli_args = [
|
||||||
|
"run",
|
||||||
|
new_path,
|
||||||
|
"--no-logs",
|
||||||
|
"--device",
|
||||||
|
CORE.address,
|
||||||
|
]
|
||||||
|
|
||||||
|
if args.dashboard:
|
||||||
|
cli_args.insert(0, "--dashboard")
|
||||||
|
|
||||||
|
try:
|
||||||
|
rc = run_external_process("esphome", *cli_args)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
rc = 1
|
||||||
|
if rc != 0:
|
||||||
|
os.remove(new_path)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
os.remove(CORE.config_path)
|
||||||
|
|
||||||
|
print(color(Fore.BOLD_GREEN, "SUCCESS"))
|
||||||
|
print()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
PRE_CONFIG_ACTIONS = {
|
PRE_CONFIG_ACTIONS = {
|
||||||
"wizard": command_wizard,
|
"wizard": command_wizard,
|
||||||
"version": command_version,
|
"version": command_version,
|
||||||
@@ -499,6 +620,7 @@ POST_CONFIG_ACTIONS = {
|
|||||||
"mqtt-fingerprint": command_mqtt_fingerprint,
|
"mqtt-fingerprint": command_mqtt_fingerprint,
|
||||||
"clean": command_clean,
|
"clean": command_clean,
|
||||||
"idedata": command_idedata,
|
"idedata": command_idedata,
|
||||||
|
"rename": command_rename,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -543,6 +665,9 @@ def parse_args(argv):
|
|||||||
parser_config.add_argument(
|
parser_config.add_argument(
|
||||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||||
)
|
)
|
||||||
|
parser_config.add_argument(
|
||||||
|
"--show-secrets", help="Show secrets in output.", action="store_true"
|
||||||
|
)
|
||||||
|
|
||||||
parser_compile = subparsers.add_parser(
|
parser_compile = subparsers.add_parser(
|
||||||
"compile", help="Read the configuration and compile a program."
|
"compile", help="Read the configuration and compile a program."
|
||||||
@@ -566,6 +691,10 @@ def parse_args(argv):
|
|||||||
"--device",
|
"--device",
|
||||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||||
)
|
)
|
||||||
|
parser_upload.add_argument(
|
||||||
|
"--file",
|
||||||
|
help="Manually specify the binary file to upload.",
|
||||||
|
)
|
||||||
|
|
||||||
parser_logs = subparsers.add_parser(
|
parser_logs = subparsers.add_parser(
|
||||||
"logs",
|
"logs",
|
||||||
@@ -681,6 +810,15 @@ def parse_args(argv):
|
|||||||
"configuration", help="Your YAML configuration file(s).", nargs=1
|
"configuration", help="Your YAML configuration file(s).", nargs=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser_rename = subparsers.add_parser(
|
||||||
|
"rename",
|
||||||
|
help="Rename a device in YAML, compile the binary and upload it.",
|
||||||
|
)
|
||||||
|
parser_rename.add_argument(
|
||||||
|
"configuration", help="Your YAML configuration file.", nargs=1
|
||||||
|
)
|
||||||
|
parser_rename.add_argument("name", help="The new name for the device.", type=str)
|
||||||
|
|
||||||
# Keep backward compatibility with the old command line format of
|
# Keep backward compatibility with the old command line format of
|
||||||
# esphome <config> <command>.
|
# esphome <config> <command>.
|
||||||
#
|
#
|
||||||
@@ -778,10 +916,10 @@ def run_esphome(argv):
|
|||||||
_LOGGER.warning("Please instead use:")
|
_LOGGER.warning("Please instead use:")
|
||||||
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
|
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
|
||||||
|
|
||||||
if sys.version_info < (3, 7, 0):
|
if sys.version_info < (3, 8, 0):
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"You're running ESPHome with Python <3.7. ESPHome is no longer compatible "
|
"You're running ESPHome with Python <3.8. ESPHome is no longer compatible "
|
||||||
"with this Python version. Please reinstall ESPHome with Python 3.7+"
|
"with this Python version. Please reinstall ESPHome with Python 3.8+"
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from esphome.const import (
|
|||||||
CONF_TYPE_ID,
|
CONF_TYPE_ID,
|
||||||
CONF_TIME,
|
CONF_TIME,
|
||||||
)
|
)
|
||||||
from esphome.jsonschema import jschema_extractor
|
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||||
from esphome.util import Registry
|
from esphome.util import Registry
|
||||||
|
|
||||||
|
|
||||||
@@ -23,11 +23,10 @@ def maybe_simple_id(*validators):
|
|||||||
def maybe_conf(conf, *validators):
|
def maybe_conf(conf, *validators):
|
||||||
validator = cv.All(*validators)
|
validator = cv.All(*validators)
|
||||||
|
|
||||||
@jschema_extractor("maybe")
|
@schema_extractor("maybe")
|
||||||
def validate(value):
|
def validate(value):
|
||||||
# pylint: disable=comparison-with-callable
|
if value == SCHEMA_EXTRACT:
|
||||||
if value == jschema_extractor:
|
return (validator, conf)
|
||||||
return validator
|
|
||||||
|
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
return validator(value)
|
return validator(value)
|
||||||
@@ -111,11 +110,9 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False):
|
|||||||
# This should only happen with invalid configs, but let's have a nice error message.
|
# This should only happen with invalid configs, but let's have a nice error message.
|
||||||
return [schema(value)]
|
return [schema(value)]
|
||||||
|
|
||||||
@jschema_extractor("automation")
|
@schema_extractor("automation")
|
||||||
def validator(value):
|
def validator(value):
|
||||||
# hack to get the schema
|
if value == SCHEMA_EXTRACT:
|
||||||
# pylint: disable=comparison-with-callable
|
|
||||||
if value == jschema_extractor:
|
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
value = validator_(value)
|
value = validator_(value)
|
||||||
@@ -262,21 +259,16 @@ async def repeat_action_to_code(config, action_id, template_arg, args):
|
|||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
def validate_wait_until(value):
|
_validate_wait_until = cv.maybe_simple_value(
|
||||||
schema = cv.Schema(
|
{
|
||||||
{
|
cv.Required(CONF_CONDITION): validate_potentially_and_condition,
|
||||||
cv.Required(CONF_CONDITION): validate_potentially_and_condition,
|
cv.Optional(CONF_TIMEOUT): cv.templatable(cv.positive_time_period_milliseconds),
|
||||||
cv.Optional(CONF_TIMEOUT): cv.templatable(
|
},
|
||||||
cv.positive_time_period_milliseconds
|
key=CONF_CONDITION,
|
||||||
),
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
if isinstance(value, dict) and CONF_CONDITION in value:
|
|
||||||
return schema(value)
|
|
||||||
return validate_wait_until({CONF_CONDITION: value})
|
|
||||||
|
|
||||||
|
|
||||||
@register_action("wait_until", WaitUntilAction, validate_wait_until)
|
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
|
||||||
async def wait_until_action_to_code(config, action_id, template_arg, args):
|
async def wait_until_action_to_code(config, action_id, template_arg, args):
|
||||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from esphome.cpp_generator import ( # noqa
|
|||||||
static_const_array,
|
static_const_array,
|
||||||
statement,
|
statement,
|
||||||
variable,
|
variable,
|
||||||
|
with_local_variable,
|
||||||
new_variable,
|
new_variable,
|
||||||
Pvariable,
|
Pvariable,
|
||||||
new_Pvariable,
|
new_Pvariable,
|
||||||
@@ -64,6 +65,7 @@ from esphome.cpp_types import ( # noqa
|
|||||||
uint64,
|
uint64,
|
||||||
int32,
|
int32,
|
||||||
int64,
|
int64,
|
||||||
|
size_t,
|
||||||
const_char_ptr,
|
const_char_ptr,
|
||||||
NAN,
|
NAN,
|
||||||
esphome_ns,
|
esphome_ns,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ void A4988::loop() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this->dir_pin_->digital_write(dir == 1);
|
this->dir_pin_->digital_write(dir == 1);
|
||||||
|
delayMicroseconds(50);
|
||||||
this->step_pin_->digital_write(true);
|
this->step_pin_->digital_write(true);
|
||||||
delayMicroseconds(5);
|
delayMicroseconds(5);
|
||||||
this->step_pin_->digital_write(false);
|
this->step_pin_->digital_write(false);
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
|
|||||||
// also take into account min_power
|
// also take into account min_power
|
||||||
auto min_us = this->cycle_time_us * this->min_power / 1000;
|
auto min_us = this->cycle_time_us * this->min_power / 1000;
|
||||||
this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
|
this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
|
||||||
|
|
||||||
if (this->method == DIM_METHOD_LEADING_PULSE) {
|
if (this->method == DIM_METHOD_LEADING_PULSE) {
|
||||||
// Minimum pulse time should be enough for the triac to trigger when it is close to the ZC zone
|
// Minimum pulse time should be enough for the triac to trigger when it is close to the ZC zone
|
||||||
// this is for brightness near 99%
|
// this is for brightness near 99%
|
||||||
@@ -202,6 +203,7 @@ void AcDimmer::setup() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void AcDimmer::write_state(float state) {
|
void AcDimmer::write_state(float state) {
|
||||||
|
state = std::acos(1 - (2 * state)) / 3.14159; // RMS power compensation
|
||||||
auto new_value = static_cast<uint16_t>(roundf(state * 65535));
|
auto new_value = static_cast<uint16_t>(roundf(state * 65535));
|
||||||
if (new_value != 0 && this->store_.value == 0)
|
if (new_value != 0 && this->store_.value == 0)
|
||||||
this->store_.init_cycle = this->init_with_half_cycle_;
|
this->store_.init_cycle = this->init_with_half_cycle_;
|
||||||
|
|||||||
@@ -11,19 +11,38 @@ ADC_MODE(ADC_VCC)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
#include <hardware/adc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
static const char *const TAG = "adc";
|
static const char *const TAG = "adc";
|
||||||
// 13 bits for S3 / 12 bit for all other esp32 variants
|
|
||||||
// create a const to avoid the repated cast to enum
|
// 13bit for S2, and 12bit for all other esp32 variants
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
||||||
|
|
||||||
|
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
|
||||||
|
#if USE_ESP32_VARIANT_ESP32S2
|
||||||
|
static const int SOC_ADC_RTC_MAX_BITWIDTH = 13;
|
||||||
|
#else
|
||||||
|
static const int SOC_ADC_RTC_MAX_BITWIDTH = 12;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit)
|
||||||
|
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
ADCSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||||
#ifndef USE_ADC_SENSOR_VCC
|
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
|
||||||
pin_->setup();
|
pin_->setup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -51,11 +70,17 @@ void ADCSensor::setup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adc_gpio_init doesn't exist on ESP32-C3 or ESP32-H2
|
|
||||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
|
||||||
adc_gpio_init(ADC_UNIT_1, (adc_channel_t) channel_);
|
|
||||||
#endif
|
|
||||||
#endif // USE_ESP32
|
#endif // USE_ESP32
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
static bool initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
adc_init();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADCSensor::dump_config() {
|
void ADCSensor::dump_config() {
|
||||||
@@ -75,22 +100,29 @@ void ADCSensor::dump_config() {
|
|||||||
} else {
|
} else {
|
||||||
switch (this->attenuation_) {
|
switch (this->attenuation_) {
|
||||||
case ADC_ATTEN_DB_0:
|
case ADC_ATTEN_DB_0:
|
||||||
ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
|
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
|
||||||
break;
|
break;
|
||||||
case ADC_ATTEN_DB_2_5:
|
case ADC_ATTEN_DB_2_5:
|
||||||
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db (max 1.5V)");
|
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
|
||||||
break;
|
break;
|
||||||
case ADC_ATTEN_DB_6:
|
case ADC_ATTEN_DB_6:
|
||||||
ESP_LOGCONFIG(TAG, " Attenuation: 6db (max 2.2V)");
|
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
|
||||||
break;
|
break;
|
||||||
case ADC_ATTEN_DB_11:
|
case ADC_ATTEN_DB_11:
|
||||||
ESP_LOGCONFIG(TAG, " Attenuation: 11db (max 3.9V)");
|
ESP_LOGCONFIG(TAG, " Attenuation: 11db");
|
||||||
break;
|
break;
|
||||||
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_ESP32
|
#endif // USE_ESP32
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
if (this->is_temperature_) {
|
||||||
|
ESP_LOGCONFIG(TAG, " Pin: Temperature");
|
||||||
|
} else {
|
||||||
|
LOG_PIN(" Pin: ", pin_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,16 +161,16 @@ float ADCSensor::sample() {
|
|||||||
return mv / 1000.0f;
|
return mv / 1000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int raw11, raw6 = 4095, raw2 = 4095, raw0 = 4095;
|
int raw11, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11);
|
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11);
|
||||||
raw11 = adc1_get_raw(channel_);
|
raw11 = adc1_get_raw(channel_);
|
||||||
if (raw11 < 4095) {
|
if (raw11 < ADC_MAX) {
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6);
|
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6);
|
||||||
raw6 = adc1_get_raw(channel_);
|
raw6 = adc1_get_raw(channel_);
|
||||||
if (raw6 < 4095) {
|
if (raw6 < ADC_MAX) {
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5);
|
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5);
|
||||||
raw2 = adc1_get_raw(channel_);
|
raw2 = adc1_get_raw(channel_);
|
||||||
if (raw2 < 4095) {
|
if (raw2 < ADC_MAX) {
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0);
|
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0);
|
||||||
raw0 = adc1_get_raw(channel_);
|
raw0 = adc1_get_raw(channel_);
|
||||||
}
|
}
|
||||||
@@ -154,20 +186,43 @@ float ADCSensor::sample() {
|
|||||||
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]);
|
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]);
|
||||||
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]);
|
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]);
|
||||||
|
|
||||||
// Contribution of each value, in range 0-2048
|
// Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
|
||||||
uint32_t c11 = std::min(raw11, 2048);
|
uint32_t c11 = std::min(raw11, ADC_HALF);
|
||||||
uint32_t c6 = 2048 - std::abs(raw6 - 2048);
|
uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
|
||||||
uint32_t c2 = 2048 - std::abs(raw2 - 2048);
|
uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
|
||||||
uint32_t c0 = std::min(4095 - raw0, 2048);
|
uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
|
||||||
// max theoretical csum value is 2048*4 = 8192
|
// max theoretical csum value is 4096*4 = 16384
|
||||||
uint32_t csum = c11 + c6 + c2 + c0;
|
uint32_t csum = c11 + c6 + c2 + c0;
|
||||||
|
|
||||||
// each mv is max 3900; so max value is 3900*2048*4, fits in unsigned
|
// each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
|
||||||
uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
|
uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
|
||||||
return mv_scaled / (float) (csum * 1000U);
|
return mv_scaled / (float) (csum * 1000U);
|
||||||
}
|
}
|
||||||
#endif // USE_ESP32
|
#endif // USE_ESP32
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
float ADCSensor::sample() {
|
||||||
|
if (this->is_temperature_) {
|
||||||
|
adc_set_temp_sensor_enabled(true);
|
||||||
|
delay(1);
|
||||||
|
adc_select_input(4);
|
||||||
|
} else {
|
||||||
|
uint8_t pin = this->pin_->get_pin();
|
||||||
|
adc_gpio_init(pin);
|
||||||
|
adc_select_input(pin - 26);
|
||||||
|
}
|
||||||
|
|
||||||
|
int raw = adc_read();
|
||||||
|
if (this->is_temperature_) {
|
||||||
|
adc_set_temp_sensor_enabled(false);
|
||||||
|
}
|
||||||
|
if (output_raw_) {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
return raw * 3.3f / 4096.0f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -38,10 +38,18 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
|||||||
std::string unique_id() override;
|
std::string unique_id() override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
void set_is_temperature() { is_temperature_ = true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InternalGPIOPin *pin_;
|
InternalGPIOPin *pin_;
|
||||||
bool output_raw_{false};
|
bool output_raw_{false};
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
bool is_temperature_{false};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||||
adc1_channel_t channel_{};
|
adc1_channel_t channel_{};
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ def validate_adc_pin(value):
|
|||||||
if str(value).upper() == "VCC":
|
if str(value).upper() == "VCC":
|
||||||
return cv.only_on_esp8266("VCC")
|
return cv.only_on_esp8266("VCC")
|
||||||
|
|
||||||
|
if str(value).upper() == "TEMPERATURE":
|
||||||
|
return cv.only_on_rp2040("TEMPERATURE")
|
||||||
|
|
||||||
if CORE.is_esp32:
|
if CORE.is_esp32:
|
||||||
value = pins.internal_gpio_input_pin_number(value)
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
variant = get_esp32_variant()
|
variant = get_esp32_variant()
|
||||||
@@ -117,6 +120,12 @@ def validate_adc_pin(value):
|
|||||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||||
)(value)
|
)(value)
|
||||||
|
|
||||||
|
if CORE.is_rp2040:
|
||||||
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
|
if value not in (26, 27, 28, 29):
|
||||||
|
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
|
||||||
|
return pins.internal_gpio_input_pin_schema(value)
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@@ -133,6 +142,7 @@ ADCSensor = adc_ns.class_(
|
|||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
ADCSensor,
|
||||||
unit_of_measurement=UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
accuracy_decimals=2,
|
accuracy_decimals=2,
|
||||||
device_class=DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
@@ -140,7 +150,6 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ADCSensor),
|
|
||||||
cv.Required(CONF_PIN): validate_adc_pin,
|
cv.Required(CONF_PIN): validate_adc_pin,
|
||||||
cv.Optional(CONF_RAW, default=False): cv.boolean,
|
cv.Optional(CONF_RAW, default=False): cv.boolean,
|
||||||
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
|
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
|
||||||
@@ -160,6 +169,8 @@ async def to_code(config):
|
|||||||
|
|
||||||
if config[CONF_PIN] == "VCC":
|
if config[CONF_PIN] == "VCC":
|
||||||
cg.add_define("USE_ADC_SENSOR_VCC")
|
cg.add_define("USE_ADC_SENSOR_VCC")
|
||||||
|
elif config[CONF_PIN] == "TEMPERATURE":
|
||||||
|
cg.add(var.set_is_temperature())
|
||||||
else:
|
else:
|
||||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||||
cg.add(var.set_pin(pin))
|
cg.add(var.set_pin(pin))
|
||||||
|
|||||||
23
esphome/components/adc128s102/__init__.py
Normal file
23
esphome/components/adc128s102/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import spi
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
DEPENDENCIES = ["spi"]
|
||||||
|
MULTI_CONF = True
|
||||||
|
CODEOWNERS = ["@DeerMaximum"]
|
||||||
|
|
||||||
|
adc128s102_ns = cg.esphome_ns.namespace("adc128s102")
|
||||||
|
ADC128S102 = adc128s102_ns.class_("ADC128S102", cg.Component, spi.SPIDevice)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ADC128S102),
|
||||||
|
}
|
||||||
|
).extend(spi.spi_device_schema(cs_pin_required=True))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await spi.register_spi_device(var, config)
|
||||||
35
esphome/components/adc128s102/adc128s102.cpp
Normal file
35
esphome/components/adc128s102/adc128s102.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "adc128s102.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace adc128s102 {
|
||||||
|
|
||||||
|
static const char *const TAG = "adc128s102";
|
||||||
|
|
||||||
|
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
|
void ADC128S102::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up adc128s102");
|
||||||
|
this->spi_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADC128S102::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "ADC128S102:");
|
||||||
|
LOG_PIN(" CS Pin:", this->cs_);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ADC128S102::read_data(uint8_t channel) {
|
||||||
|
uint8_t control = channel << 3;
|
||||||
|
|
||||||
|
this->enable();
|
||||||
|
uint8_t adc_primary_byte = this->transfer_byte(control);
|
||||||
|
uint8_t adc_secondary_byte = this->transfer_byte(0x00);
|
||||||
|
this->disable();
|
||||||
|
|
||||||
|
uint16_t digital_value = adc_primary_byte << 8 | adc_secondary_byte;
|
||||||
|
|
||||||
|
return digital_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace adc128s102
|
||||||
|
} // namespace esphome
|
||||||
23
esphome/components/adc128s102/adc128s102.h
Normal file
23
esphome/components/adc128s102/adc128s102.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace adc128s102 {
|
||||||
|
|
||||||
|
class ADC128S102 : public Component,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||||
|
spi::DATA_RATE_10MHZ> {
|
||||||
|
public:
|
||||||
|
ADC128S102() = default;
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
uint16_t read_data(uint8_t channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace adc128s102
|
||||||
|
} // namespace esphome
|
||||||
35
esphome/components/adc128s102/sensor/__init__.py
Normal file
35
esphome/components/adc128s102/sensor/__init__.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor, voltage_sampler
|
||||||
|
from esphome.const import CONF_ID, CONF_CHANNEL
|
||||||
|
|
||||||
|
from .. import adc128s102_ns, ADC128S102
|
||||||
|
|
||||||
|
AUTO_LOAD = ["voltage_sampler"]
|
||||||
|
DEPENDENCIES = ["adc128s102"]
|
||||||
|
|
||||||
|
ADC128S102Sensor = adc128s102_ns.class_(
|
||||||
|
"ADC128S102Sensor",
|
||||||
|
sensor.Sensor,
|
||||||
|
cg.PollingComponent,
|
||||||
|
voltage_sampler.VoltageSampler,
|
||||||
|
)
|
||||||
|
CONF_ADC128S102_ID = "adc128s102_id"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ADC128S102Sensor),
|
||||||
|
cv.GenerateID(CONF_ADC128S102_ID): cv.use_id(ADC128S102),
|
||||||
|
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
|
||||||
|
}
|
||||||
|
).extend(cv.polling_component_schema("60s"))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(
|
||||||
|
config[CONF_ID],
|
||||||
|
config[CONF_CHANNEL],
|
||||||
|
)
|
||||||
|
await cg.register_parented(var, config[CONF_ADC128S102_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await sensor.register_sensor(var, config)
|
||||||
24
esphome/components/adc128s102/sensor/adc128s102_sensor.cpp
Normal file
24
esphome/components/adc128s102/sensor/adc128s102_sensor.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#include "adc128s102_sensor.h"
|
||||||
|
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace adc128s102 {
|
||||||
|
|
||||||
|
static const char *const TAG = "adc128s102.sensor";
|
||||||
|
|
||||||
|
ADC128S102Sensor::ADC128S102Sensor(uint8_t channel) : channel_(channel) {}
|
||||||
|
|
||||||
|
float ADC128S102Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
void ADC128S102Sensor::dump_config() {
|
||||||
|
LOG_SENSOR("", "ADC128S102 Sensor", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " Pin: %u", this->channel_);
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ADC128S102Sensor::sample() { return this->parent_->read_data(this->channel_); }
|
||||||
|
void ADC128S102Sensor::update() { this->publish_state(this->sample()); }
|
||||||
|
|
||||||
|
} // namespace adc128s102
|
||||||
|
} // namespace esphome
|
||||||
29
esphome/components/adc128s102/sensor/adc128s102_sensor.h
Normal file
29
esphome/components/adc128s102/sensor/adc128s102_sensor.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
|
#include "../adc128s102.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace adc128s102 {
|
||||||
|
|
||||||
|
class ADC128S102Sensor : public PollingComponent,
|
||||||
|
public Parented<ADC128S102>,
|
||||||
|
public sensor::Sensor,
|
||||||
|
public voltage_sampler::VoltageSampler {
|
||||||
|
public:
|
||||||
|
ADC128S102Sensor(uint8_t channel);
|
||||||
|
|
||||||
|
void update() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
float sample() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t channel_;
|
||||||
|
};
|
||||||
|
} // namespace adc128s102
|
||||||
|
} // namespace esphome
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "esphome/components/display/display_buffer.h"
|
#include "esphome/components/display/display_buffer.h"
|
||||||
#include "esphome/components/light/addressable_light.h"
|
#include "esphome/components/light/addressable_light.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace addressable_light {
|
namespace addressable_light {
|
||||||
|
|
||||||
@@ -40,6 +42,8 @@ class AddressableLightDisplay : public display::DisplayBuffer, public PollingCom
|
|||||||
void setup() override;
|
void setup() override;
|
||||||
void display();
|
void display();
|
||||||
|
|
||||||
|
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int get_width_internal() override;
|
int get_width_internal() override;
|
||||||
int get_height_internal() override;
|
int get_height_internal() override;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "esphome/components/i2c/i2c.h"
|
#include "esphome/components/i2c/i2c.h"
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ade7953 {
|
namespace ade7953 {
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ class ADE7953 : public i2c::I2CDevice, public PollingComponent {
|
|||||||
return i2c::ERROR_OK;
|
return i2c::ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalGPIOPin *irq_pin_ = nullptr;
|
InternalGPIOPin *irq_pin_{nullptr};
|
||||||
bool is_setup_{false};
|
bool is_setup_{false};
|
||||||
sensor::Sensor *voltage_sensor_{nullptr};
|
sensor::Sensor *voltage_sensor_{nullptr};
|
||||||
sensor::Sensor *current_a_sensor_{nullptr};
|
sensor::Sensor *current_a_sensor_{nullptr};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ static const char *const TAG = "ads1115";
|
|||||||
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
||||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
||||||
|
|
||||||
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111;
|
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
|
||||||
|
|
||||||
void ADS1115Component::setup() {
|
void ADS1115Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
|
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
|
||||||
@@ -18,6 +18,9 @@ void ADS1115Component::setup() {
|
|||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGCONFIG(TAG, "Configuring ADS1115...");
|
||||||
|
|
||||||
uint16_t config = 0;
|
uint16_t config = 0;
|
||||||
// Clear single-shot bit
|
// Clear single-shot bit
|
||||||
// 0b0xxxxxxxxxxxxxxx
|
// 0b0xxxxxxxxxxxxxxx
|
||||||
@@ -77,6 +80,7 @@ void ADS1115Component::dump_config() {
|
|||||||
LOG_SENSOR(" ", "Sensor", sensor);
|
LOG_SENSOR(" ", "Sensor", sensor);
|
||||||
ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer());
|
ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer());
|
||||||
ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain());
|
ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain());
|
||||||
|
ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
|
float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
|
||||||
@@ -127,27 +131,45 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
|
|||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return NAN;
|
return NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sensor->get_resolution() == ADS1015_12_BITS) {
|
||||||
|
bool negative = (raw_conversion >> 15) == 1;
|
||||||
|
|
||||||
|
// shift raw_conversion as it's only 12-bits, left justified
|
||||||
|
raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS);
|
||||||
|
|
||||||
|
// check if number was negative in order to keep the sign
|
||||||
|
if (negative) {
|
||||||
|
// the number was negative
|
||||||
|
// 1) set the negative bit back
|
||||||
|
raw_conversion |= 0x8000;
|
||||||
|
// 2) reset the former (shifted) negative bit
|
||||||
|
raw_conversion &= 0xF7FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto signed_conversion = static_cast<int16_t>(raw_conversion);
|
auto signed_conversion = static_cast<int16_t>(raw_conversion);
|
||||||
|
|
||||||
float millivolts;
|
float millivolts;
|
||||||
|
float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
|
||||||
switch (sensor->get_gain()) {
|
switch (sensor->get_gain()) {
|
||||||
case ADS1115_GAIN_6P144:
|
case ADS1115_GAIN_6P144:
|
||||||
millivolts = signed_conversion * 0.187500f;
|
millivolts = (signed_conversion * 6144) / divider;
|
||||||
break;
|
break;
|
||||||
case ADS1115_GAIN_4P096:
|
case ADS1115_GAIN_4P096:
|
||||||
millivolts = signed_conversion * 0.125000f;
|
millivolts = (signed_conversion * 4096) / divider;
|
||||||
break;
|
break;
|
||||||
case ADS1115_GAIN_2P048:
|
case ADS1115_GAIN_2P048:
|
||||||
millivolts = signed_conversion * 0.062500f;
|
millivolts = (signed_conversion * 2048) / divider;
|
||||||
break;
|
break;
|
||||||
case ADS1115_GAIN_1P024:
|
case ADS1115_GAIN_1P024:
|
||||||
millivolts = signed_conversion * 0.031250f;
|
millivolts = (signed_conversion * 1024) / divider;
|
||||||
break;
|
break;
|
||||||
case ADS1115_GAIN_0P512:
|
case ADS1115_GAIN_0P512:
|
||||||
millivolts = signed_conversion * 0.015625f;
|
millivolts = (signed_conversion * 512) / divider;
|
||||||
break;
|
break;
|
||||||
case ADS1115_GAIN_0P256:
|
case ADS1115_GAIN_0P256:
|
||||||
millivolts = signed_conversion * 0.007813f;
|
millivolts = (signed_conversion * 256) / divider;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
millivolts = NAN;
|
millivolts = NAN;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "esphome/components/i2c/i2c.h"
|
#include "esphome/components/i2c/i2c.h"
|
||||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ads1115 {
|
namespace ads1115 {
|
||||||
|
|
||||||
@@ -28,6 +30,11 @@ enum ADS1115Gain {
|
|||||||
ADS1115_GAIN_0P256 = 0b101,
|
ADS1115_GAIN_0P256 = 0b101,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ADS1115Resolution {
|
||||||
|
ADS1115_16_BITS = 16,
|
||||||
|
ADS1015_12_BITS = 12,
|
||||||
|
};
|
||||||
|
|
||||||
class ADS1115Sensor;
|
class ADS1115Sensor;
|
||||||
|
|
||||||
class ADS1115Component : public Component, public i2c::I2CDevice {
|
class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||||
@@ -56,15 +63,17 @@ class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public vol
|
|||||||
void update() override;
|
void update() override;
|
||||||
void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
|
void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
|
||||||
void set_gain(ADS1115Gain gain) { gain_ = gain; }
|
void set_gain(ADS1115Gain gain) { gain_ = gain; }
|
||||||
|
void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; }
|
||||||
float sample() override;
|
float sample() override;
|
||||||
uint8_t get_multiplexer() const { return multiplexer_; }
|
uint8_t get_multiplexer() const { return multiplexer_; }
|
||||||
uint8_t get_gain() const { return gain_; }
|
uint8_t get_gain() const { return gain_; }
|
||||||
|
uint8_t get_resolution() const { return resolution_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ADS1115Component *parent_;
|
ADS1115Component *parent_;
|
||||||
ADS1115Multiplexer multiplexer_;
|
ADS1115Multiplexer multiplexer_;
|
||||||
ADS1115Gain gain_;
|
ADS1115Gain gain_;
|
||||||
|
ADS1115Resolution resolution_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ads1115
|
} // namespace ads1115
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from esphome.components import sensor, voltage_sampler
|
|||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_GAIN,
|
CONF_GAIN,
|
||||||
CONF_MULTIPLEXER,
|
CONF_MULTIPLEXER,
|
||||||
|
CONF_RESOLUTION,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
@@ -35,6 +36,12 @@ GAIN = {
|
|||||||
"0.256": ADS1115Gain.ADS1115_GAIN_0P256,
|
"0.256": ADS1115Gain.ADS1115_GAIN_0P256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ADS1115Resolution = ads1115_ns.enum("ADS1115Resolution")
|
||||||
|
RESOLUTION = {
|
||||||
|
"16_BITS": ADS1115Resolution.ADS1115_16_BITS,
|
||||||
|
"12_BITS": ADS1115Resolution.ADS1015_12_BITS,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def validate_gain(value):
|
def validate_gain(value):
|
||||||
if isinstance(value, float):
|
if isinstance(value, float):
|
||||||
@@ -52,6 +59,7 @@ ADS1115Sensor = ads1115_ns.class_(
|
|||||||
CONF_ADS1115_ID = "ads1115_id"
|
CONF_ADS1115_ID = "ads1115_id"
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
ADS1115Sensor,
|
||||||
unit_of_measurement=UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
accuracy_decimals=3,
|
accuracy_decimals=3,
|
||||||
device_class=DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
@@ -59,10 +67,12 @@ CONFIG_SCHEMA = (
|
|||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ADS1115Sensor),
|
|
||||||
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
|
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
|
||||||
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
|
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
|
||||||
cv.Required(CONF_GAIN): validate_gain,
|
cv.Required(CONF_GAIN): validate_gain,
|
||||||
|
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
|
||||||
|
RESOLUTION, upper=True, space="_"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("60s"))
|
.extend(cv.polling_component_schema("60s"))
|
||||||
@@ -77,5 +87,6 @@ async def to_code(config):
|
|||||||
|
|
||||||
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
||||||
cg.add(var.set_gain(config[CONF_GAIN]))
|
cg.add(var.set_gain(config[CONF_GAIN]))
|
||||||
|
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
|
||||||
|
|
||||||
cg.add(paren.register_sensor(var))
|
cg.add(paren.register_sensor(var))
|
||||||
|
|||||||
@@ -122,8 +122,9 @@ void AHT10Component::update() {
|
|||||||
this->temperature_sensor_->publish_state(temperature);
|
this->temperature_sensor_->publish_state(temperature);
|
||||||
}
|
}
|
||||||
if (this->humidity_sensor_ != nullptr) {
|
if (this->humidity_sensor_ != nullptr) {
|
||||||
if (std::isnan(humidity))
|
if (std::isnan(humidity)) {
|
||||||
ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
|
ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
|
||||||
|
}
|
||||||
this->humidity_sensor_->publish_state(humidity);
|
this->humidity_sensor_->publish_state(humidity);
|
||||||
}
|
}
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice {
|
|||||||
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
|
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
sensor::Sensor *temperature_sensor_;
|
sensor::Sensor *temperature_sensor_{nullptr};
|
||||||
sensor::Sensor *humidity_sensor_;
|
sensor::Sensor *humidity_sensor_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aht10
|
} // namespace aht10
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ESP_GATTC_READ_CHAR_EVT: {
|
case ESP_GATTC_READ_CHAR_EVT: {
|
||||||
if (param->read.conn_id != this->parent()->conn_id)
|
if (param->read.conn_id != this->parent()->get_conn_id())
|
||||||
break;
|
break;
|
||||||
if (param->read.status != ESP_GATT_OK) {
|
if (param->read.status != ESP_GATT_OK) {
|
||||||
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
|
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
|
||||||
@@ -88,8 +88,8 @@ void AirthingsWaveMini::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AirthingsWaveMini::request_read_values_() {
|
void AirthingsWaveMini::request_read_values_() {
|
||||||
auto status =
|
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_,
|
||||||
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle_, ESP_GATT_AUTH_REQ_NONE);
|
ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
|
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ESP_GATTC_READ_CHAR_EVT: {
|
case ESP_GATTC_READ_CHAR_EVT: {
|
||||||
if (param->read.conn_id != this->parent()->conn_id)
|
if (param->read.conn_id != this->parent()->get_conn_id())
|
||||||
break;
|
break;
|
||||||
if (param->read.status != ESP_GATT_OK) {
|
if (param->read.status != ESP_GATT_OK) {
|
||||||
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
|
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
|
||||||
@@ -109,8 +109,8 @@ void AirthingsWavePlus::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AirthingsWavePlus::request_read_values_() {
|
void AirthingsWavePlus::request_read_values_() {
|
||||||
auto status =
|
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_,
|
||||||
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle_, ESP_GATT_AUTH_REQ_NONE);
|
ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
|
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,33 +4,15 @@
|
|||||||
// - Arduino - AM2320: https://github.com/EngDial/AM2320/blob/master/src/AM2320.cpp
|
// - Arduino - AM2320: https://github.com/EngDial/AM2320/blob/master/src/AM2320.cpp
|
||||||
|
|
||||||
#include "am2320.h"
|
#include "am2320.h"
|
||||||
#include "esphome/core/log.h"
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace am2320 {
|
namespace am2320 {
|
||||||
|
|
||||||
static const char *const TAG = "am2320";
|
static const char *const TAG = "am2320";
|
||||||
|
|
||||||
// ---=== Calc CRC16 ===---
|
|
||||||
uint16_t crc_16(uint8_t *ptr, uint8_t length) {
|
|
||||||
uint16_t crc = 0xFFFF;
|
|
||||||
uint8_t i;
|
|
||||||
//------------------------------
|
|
||||||
while (length--) {
|
|
||||||
crc ^= *ptr++;
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
if ((crc & 0x01) != 0) {
|
|
||||||
crc >>= 1;
|
|
||||||
crc ^= 0xA001;
|
|
||||||
} else {
|
|
||||||
crc >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AM2320Component::update() {
|
void AM2320Component::update() {
|
||||||
uint8_t data[8];
|
uint8_t data[8];
|
||||||
data[0] = 0;
|
data[0] = 0;
|
||||||
@@ -98,7 +80,7 @@ bool AM2320Component::read_data_(uint8_t *data) {
|
|||||||
checksum = data[7] << 8;
|
checksum = data[7] << 8;
|
||||||
checksum += data[6];
|
checksum += data[6];
|
||||||
|
|
||||||
if (crc_16(data, 6) != checksum) {
|
if (crc16(data, 6) != checksum) {
|
||||||
ESP_LOGW(TAG, "AM2320 Checksum invalid!");
|
ESP_LOGW(TAG, "AM2320 Checksum invalid!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ class AM2320Component : public PollingComponent, public i2c::I2CDevice {
|
|||||||
bool read_data_(uint8_t *data);
|
bool read_data_(uint8_t *data);
|
||||||
bool read_bytes_(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0);
|
bool read_bytes_(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0);
|
||||||
|
|
||||||
sensor::Sensor *temperature_sensor_;
|
sensor::Sensor *temperature_sensor_{nullptr};
|
||||||
sensor::Sensor *humidity_sensor_;
|
sensor::Sensor *humidity_sensor_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace am2320
|
} // namespace am2320
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
|
|||||||
if (this->current_sensor_ > 0) {
|
if (this->current_sensor_ > 0) {
|
||||||
if (this->illuminance_ != nullptr) {
|
if (this->illuminance_ != nullptr) {
|
||||||
auto *packet = this->encoder_->get_light_level_request();
|
auto *packet = this->encoder_->get_light_level_request();
|
||||||
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
|
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
|
this->char_handle_, packet->length, packet->data,
|
||||||
ESP_GATT_AUTH_REQ_NONE);
|
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
|
||||||
status);
|
status);
|
||||||
@@ -102,10 +102,11 @@ void Am43::update() {
|
|||||||
if (this->battery_ != nullptr) {
|
if (this->battery_ != nullptr) {
|
||||||
auto *packet = this->encoder_->get_battery_level_request();
|
auto *packet = this->encoder_->get_battery_level_request();
|
||||||
auto status =
|
auto status =
|
||||||
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status)
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this->current_sensor_++;
|
this->current_sensor_++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ void Am43Component::loop() {
|
|||||||
if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) {
|
if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) {
|
||||||
auto *packet = this->encoder_->get_send_pin_request(this->pin_);
|
auto *packet = this->encoder_->get_send_pin_request(this->pin_);
|
||||||
auto status =
|
auto status =
|
||||||
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
|
ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
|
||||||
@@ -54,10 +54,11 @@ void Am43Component::control(const CoverCall &call) {
|
|||||||
if (call.get_stop()) {
|
if (call.get_stop()) {
|
||||||
auto *packet = this->encoder_->get_stop_request();
|
auto *packet = this->encoder_->get_stop_request();
|
||||||
auto status =
|
auto status =
|
||||||
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status)
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (call.get_position().has_value()) {
|
if (call.get_position().has_value()) {
|
||||||
auto pos = *call.get_position();
|
auto pos = *call.get_position();
|
||||||
@@ -66,10 +67,11 @@ void Am43Component::control(const CoverCall &call) {
|
|||||||
pos = 1 - pos;
|
pos = 1 - pos;
|
||||||
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
|
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
|
||||||
auto status =
|
auto status =
|
||||||
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status)
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +94,8 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
|||||||
}
|
}
|
||||||
this->char_handle_ = chr->handle;
|
this->char_handle_ = chr->handle;
|
||||||
|
|
||||||
auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle);
|
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||||
|
chr->handle);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||||
}
|
}
|
||||||
@@ -122,21 +125,24 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
|||||||
if (this->decoder_->pin_ok_) {
|
if (this->decoder_->pin_ok_) {
|
||||||
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
|
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
|
||||||
auto *packet = this->encoder_->get_position_request();
|
auto *packet = this->encoder_->get_position_request();
|
||||||
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
|
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
|
this->char_handle_, packet->length, packet->data,
|
||||||
ESP_GATT_AUTH_REQ_NONE);
|
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status)
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
|
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_)
|
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
|
||||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
|
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_)
|
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
|
||||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
|
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
1
esphome/components/analog_threshold/__init__.py
Normal file
1
esphome/components/analog_threshold/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CODEOWNERS = ["@ianchi"]
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "analog_threshold_binary_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace analog_threshold {
|
||||||
|
|
||||||
|
static const char *const TAG = "analog_threshold.binary_sensor";
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::setup() {
|
||||||
|
float sensor_value = this->sensor_->get_state();
|
||||||
|
|
||||||
|
// TRUE state is defined to be when sensor is >= threshold
|
||||||
|
// so when undefined sensor value initialize to FALSE
|
||||||
|
if (std::isnan(sensor_value)) {
|
||||||
|
this->publish_initial_state(false);
|
||||||
|
} else {
|
||||||
|
this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
||||||
|
this->sensor_ = analog_sensor;
|
||||||
|
|
||||||
|
this->sensor_->add_on_state_callback([this](float sensor_value) {
|
||||||
|
// if there is an invalid sensor reading, ignore the change and keep the current state
|
||||||
|
if (!std::isnan(sensor_value)) {
|
||||||
|
this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::dump_config() {
|
||||||
|
LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
|
||||||
|
LOG_SENSOR(" ", "Sensor", this->sensor_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace analog_threshold
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace analog_threshold {
|
||||||
|
|
||||||
|
class AnalogThresholdBinarySensor : public Component, public binary_sensor::BinarySensor {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
void setup() override;
|
||||||
|
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
void set_sensor(sensor::Sensor *analog_sensor);
|
||||||
|
void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; }
|
||||||
|
void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sensor::Sensor *sensor_{nullptr};
|
||||||
|
|
||||||
|
float upper_threshold_;
|
||||||
|
float lower_threshold_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace analog_threshold
|
||||||
|
} // namespace esphome
|
||||||
44
esphome/components/analog_threshold/binary_sensor.py
Normal file
44
esphome/components/analog_threshold/binary_sensor.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import binary_sensor, sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_SENSOR_ID,
|
||||||
|
CONF_THRESHOLD,
|
||||||
|
)
|
||||||
|
|
||||||
|
analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold")
|
||||||
|
|
||||||
|
AnalogThresholdBinarySensor = analog_threshold_ns.class_(
|
||||||
|
"AnalogThresholdBinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_UPPER = "upper"
|
||||||
|
CONF_LOWER = "lower"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(AnalogThresholdBinarySensor),
|
||||||
|
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
||||||
|
cv.Required(CONF_THRESHOLD): cv.Any(
|
||||||
|
cv.float_,
|
||||||
|
cv.Schema(
|
||||||
|
{cv.Required(CONF_UPPER): cv.float_, cv.Required(CONF_LOWER): cv.float_}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
sens = await cg.get_variable(config[CONF_SENSOR_ID])
|
||||||
|
cg.add(var.set_sensor(sens))
|
||||||
|
|
||||||
|
if isinstance(config[CONF_THRESHOLD], float):
|
||||||
|
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD]))
|
||||||
|
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD]))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER]))
|
||||||
|
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER]))
|
||||||
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
DEPENDENCIES = ["display"]
|
DEPENDENCIES = ["display"]
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
|
||||||
Animation_ = display.display_ns.class_("Animation")
|
Animation_ = display.display_ns.class_("Animation", espImage.Image_)
|
||||||
|
|
||||||
ANIMATION_SCHEMA = cv.Schema(
|
ANIMATION_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
@@ -94,7 +94,30 @@ async def to_code(config):
|
|||||||
data[pos] = pix[2]
|
data[pos] = pix[2]
|
||||||
pos += 1
|
pos += 1
|
||||||
|
|
||||||
elif config[CONF_TYPE] == "BINARY":
|
elif config[CONF_TYPE] == "RGB565":
|
||||||
|
data = [0 for _ in range(height * width * 2 * frames)]
|
||||||
|
pos = 0
|
||||||
|
for frameIndex in range(frames):
|
||||||
|
image.seek(frameIndex)
|
||||||
|
frame = image.convert("RGB")
|
||||||
|
if CONF_RESIZE in config:
|
||||||
|
frame = frame.resize([width, height])
|
||||||
|
pixels = list(frame.getdata())
|
||||||
|
if len(pixels) != height * width:
|
||||||
|
raise core.EsphomeError(
|
||||||
|
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
|
||||||
|
)
|
||||||
|
for pix in pixels:
|
||||||
|
R = pix[0] >> 3
|
||||||
|
G = pix[1] >> 2
|
||||||
|
B = pix[2] >> 3
|
||||||
|
rgb = (R << 11) | (G << 5) | B
|
||||||
|
data[pos] = rgb >> 8
|
||||||
|
pos += 1
|
||||||
|
data[pos] = rgb & 255
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
|
||||||
width8 = ((width + 7) // 8) * 8
|
width8 = ((width + 7) // 8) * 8
|
||||||
data = [0 for _ in range((height * width8 // 8) * frames)]
|
data = [0 for _ in range((height * width8 // 8) * frames)]
|
||||||
for frameIndex in range(frames):
|
for frameIndex in range(frames):
|
||||||
|
|||||||
@@ -34,17 +34,21 @@ void Anova::control(const ClimateCall &call) {
|
|||||||
ESP_LOGW(TAG, "Unsupported mode: %d", mode);
|
ESP_LOGW(TAG, "Unsupported mode: %d", mode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
|
auto status =
|
||||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
if (status)
|
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (call.get_target_temperature().has_value()) {
|
if (call.get_target_temperature().has_value()) {
|
||||||
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
|
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
|
||||||
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
|
auto status =
|
||||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
if (status)
|
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +69,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
|||||||
}
|
}
|
||||||
this->char_handle_ = chr->handle;
|
this->char_handle_ = chr->handle;
|
||||||
|
|
||||||
auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle);
|
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||||
|
chr->handle);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||||
}
|
}
|
||||||
@@ -92,7 +97,7 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
|||||||
}
|
}
|
||||||
if (this->codec_->has_unit()) {
|
if (this->codec_->has_unit()) {
|
||||||
this->fahrenheit_ = (this->codec_->unit_ == 'f');
|
this->fahrenheit_ = (this->codec_->unit_ == 'f');
|
||||||
ESP_LOGD(TAG, "Anova units is %s", this->fahrenheit_ ? "fahrenheit" : "celcius");
|
ESP_LOGD(TAG, "Anova units is %s", this->fahrenheit_ ? "fahrenheit" : "celsius");
|
||||||
this->current_request_++;
|
this->current_request_++;
|
||||||
}
|
}
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
@@ -112,8 +117,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
|||||||
}
|
}
|
||||||
if (pkt != nullptr) {
|
if (pkt != nullptr) {
|
||||||
auto status =
|
auto status =
|
||||||
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length,
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
if (status) {
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
|
||||||
status);
|
status);
|
||||||
@@ -137,10 +142,12 @@ void Anova::update() {
|
|||||||
auto *pkt = this->codec_->get_read_device_status_request();
|
auto *pkt = this->codec_->get_read_device_status_request();
|
||||||
if (this->current_request_ == 0)
|
if (this->current_request_ == 0)
|
||||||
this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c');
|
this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c');
|
||||||
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
|
auto status =
|
||||||
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
if (status)
|
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
|
if (status) {
|
||||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||||
|
}
|
||||||
this->current_request_++;
|
this->current_request_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,27 @@ AUTO_LOAD = ["sensor", "binary_sensor"]
|
|||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
|
||||||
CONF_APDS9960_ID = "apds9960_id"
|
CONF_APDS9960_ID = "apds9960_id"
|
||||||
|
CONF_LED_DRIVE = "led_drive"
|
||||||
|
CONF_PROXIMITY_GAIN = "proximity_gain"
|
||||||
|
CONF_AMBIENT_LIGHT_GAIN = "ambient_light_gain"
|
||||||
|
CONF_GESTURE_LED_DRIVE = "gesture_led_drive"
|
||||||
|
CONF_GESTURE_GAIN = "gesture_gain"
|
||||||
|
CONF_GESTURE_WAIT_TIME = "gesture_wait_time"
|
||||||
|
|
||||||
|
DRIVE_LEVELS = {"100ma": 0, "50ma": 1, "25ma": 2, "12.5ma": 3}
|
||||||
|
PROXIMITY_LEVELS = {"1x": 0, "2x": 1, "4x": 2, "8x": 3}
|
||||||
|
AMBIENT_LEVELS = {"1x": 0, "4x": 1, "16x": 2, "64x": 3}
|
||||||
|
GESTURE_LEVELS = {"1x": 0, "2x": 1, "4x": 2, "8x": 3}
|
||||||
|
GESTURE_WAIT_TIMES = {
|
||||||
|
"0ms": 0,
|
||||||
|
"2.8ms": 1,
|
||||||
|
"5.6ms": 2,
|
||||||
|
"8.4ms": 3,
|
||||||
|
"14ms": 4,
|
||||||
|
"22.4ms": 5,
|
||||||
|
"30.8ms": 6,
|
||||||
|
"39.2ms": 7,
|
||||||
|
}
|
||||||
|
|
||||||
apds9960_nds = cg.esphome_ns.namespace("apds9960")
|
apds9960_nds = cg.esphome_ns.namespace("apds9960")
|
||||||
APDS9960 = apds9960_nds.class_("APDS9960", cg.PollingComponent, i2c.I2CDevice)
|
APDS9960 = apds9960_nds.class_("APDS9960", cg.PollingComponent, i2c.I2CDevice)
|
||||||
@@ -16,6 +37,20 @@ CONFIG_SCHEMA = (
|
|||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(APDS9960),
|
cv.GenerateID(): cv.declare_id(APDS9960),
|
||||||
|
cv.Optional(CONF_LED_DRIVE, "100mA"): cv.enum(DRIVE_LEVELS, lower=True),
|
||||||
|
cv.Optional(CONF_PROXIMITY_GAIN, "4x"): cv.enum(
|
||||||
|
PROXIMITY_LEVELS, lower=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_AMBIENT_LIGHT_GAIN, "4x"): cv.enum(
|
||||||
|
AMBIENT_LEVELS, lower=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GESTURE_LED_DRIVE, "100mA"): cv.enum(
|
||||||
|
DRIVE_LEVELS, lower=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GESTURE_GAIN, "4x"): cv.enum(GESTURE_LEVELS, lower=True),
|
||||||
|
cv.Optional(CONF_GESTURE_WAIT_TIME, "2.8ms"): cv.enum(
|
||||||
|
GESTURE_WAIT_TIMES, lower=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("60s"))
|
.extend(cv.polling_component_schema("60s"))
|
||||||
@@ -27,3 +62,9 @@ async def to_code(config):
|
|||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await i2c.register_i2c_device(var, config)
|
await i2c.register_i2c_device(var, config)
|
||||||
|
cg.add(var.set_led_drive(config[CONF_LED_DRIVE]))
|
||||||
|
cg.add(var.set_proximity_gain(config[CONF_PROXIMITY_GAIN]))
|
||||||
|
cg.add(var.set_ambient_gain(config[CONF_AMBIENT_LIGHT_GAIN]))
|
||||||
|
cg.add(var.set_gesture_led_drive(config[CONF_GESTURE_LED_DRIVE]))
|
||||||
|
cg.add(var.set_gesture_gain(config[CONF_GESTURE_GAIN]))
|
||||||
|
cg.add(var.set_gesture_wait_time(config[CONF_GESTURE_WAIT_TIME]))
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ void APDS9960::setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id != 0xAB && id != 0x9C) { // APDS9960 all should have one of these IDs
|
if (id != 0xAB && id != 0x9C && id != 0xA8) { // APDS9960 all should have one of these IDs
|
||||||
this->error_code_ = WRONG_ID;
|
this->error_code_ = WRONG_ID;
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
@@ -46,16 +46,16 @@ void APDS9960::setup() {
|
|||||||
uint8_t val = 0;
|
uint8_t val = 0;
|
||||||
APDS9960_ERROR_CHECK(this->read_byte(0x8F, &val));
|
APDS9960_ERROR_CHECK(this->read_byte(0x8F, &val));
|
||||||
val &= 0b00111111;
|
val &= 0b00111111;
|
||||||
uint8_t led_drive = 0; // led drive, 0 -> 100mA, 1 -> 50mA, 2 -> 25mA, 3 -> 12.5mA
|
// led drive, 0 -> 100mA, 1 -> 50mA, 2 -> 25mA, 3 -> 12.5mA
|
||||||
val |= (led_drive & 0b11) << 6;
|
val |= (this->led_drive_ & 0b11) << 6;
|
||||||
|
|
||||||
val &= 0b11110011;
|
val &= 0b11110011;
|
||||||
uint8_t proximity_gain = 2; // proximity gain, 0 -> 1x, 1 -> 2X, 2 -> 4X, 4 -> 8X
|
// proximity gain, 0 -> 1x, 1 -> 2X, 2 -> 4X, 3 -> 8X
|
||||||
val |= (proximity_gain & 0b11) << 2;
|
val |= (this->proximity_gain_ & 0b11) << 2;
|
||||||
|
|
||||||
val &= 0b11111100;
|
val &= 0b11111100;
|
||||||
uint8_t ambient_gain = 1; // ambient light gain, 0 -> 1x, 1 -> 4x, 2 -> 16x, 3 -> 64x
|
// ambient light gain, 0 -> 1x, 1 -> 4x, 2 -> 16x, 3 -> 64x
|
||||||
val |= (ambient_gain & 0b11) << 0;
|
val |= (this->ambient_gain_ & 0b11) << 0;
|
||||||
APDS9960_WRITE_BYTE(0x8F, val);
|
APDS9960_WRITE_BYTE(0x8F, val);
|
||||||
|
|
||||||
// Pers (0x8C) -> 0x11 (2 consecutive proximity or ALS for interrupt)
|
// Pers (0x8C) -> 0x11 (2 consecutive proximity or ALS for interrupt)
|
||||||
@@ -75,19 +75,18 @@ void APDS9960::setup() {
|
|||||||
// GConf 2 (0xA3, gesture config 2) ->
|
// GConf 2 (0xA3, gesture config 2) ->
|
||||||
APDS9960_ERROR_CHECK(this->read_byte(0xA3, &val));
|
APDS9960_ERROR_CHECK(this->read_byte(0xA3, &val));
|
||||||
val &= 0b10011111;
|
val &= 0b10011111;
|
||||||
uint8_t gesture_gain = 2; // gesture gain, 0 -> 1x, 1 -> 2x, 2 -> 4x, 3 -> 8x
|
// gesture gain, 0 -> 1x, 1 -> 2x, 2 -> 4x, 3 -> 8x
|
||||||
val |= (gesture_gain & 0b11) << 5;
|
val |= (this->gesture_gain_ & 0b11) << 5;
|
||||||
|
|
||||||
val &= 0b11100111;
|
val &= 0b11100111;
|
||||||
uint8_t gesture_led_drive = 0; // gesture led drive, 0 -> 100mA, 1 -> 50mA, 2 -> 25mA, 3 -> 12.5mA
|
// gesture led drive, 0 -> 100mA, 1 -> 50mA, 2 -> 25mA, 3 -> 12.5mA
|
||||||
val |= (gesture_led_drive & 0b11) << 3;
|
val |= (this->gesture_led_drive_ & 0b11) << 3;
|
||||||
|
|
||||||
val &= 0b11111000;
|
val &= 0b11111000;
|
||||||
// gesture wait time
|
// gesture wait time
|
||||||
// 0 -> 0ms, 1 -> 2.8ms, 2 -> 5.6ms, 3 -> 8.4ms
|
// 0 -> 0ms, 1 -> 2.8ms, 2 -> 5.6ms, 3 -> 8.4ms
|
||||||
// 4 -> 14.0ms, 5 -> 22.4 ms, 6 -> 30.8ms, 7 -> 39.2 ms
|
// 4 -> 14.0ms, 5 -> 22.4 ms, 6 -> 30.8ms, 7 -> 39.2 ms
|
||||||
uint8_t gesture_wait_time = 1; // gesture wait time
|
val |= (this->gesture_wait_time_ & 0b111) << 0;
|
||||||
val |= (gesture_wait_time & 0b111) << 0;
|
|
||||||
APDS9960_WRITE_BYTE(0xA3, val);
|
APDS9960_WRITE_BYTE(0xA3, val);
|
||||||
|
|
||||||
// GOffsetU (0xA4) -> 0x00 (no offset)
|
// GOffsetU (0xA4) -> 0x00 (no offset)
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
|||||||
void update() override;
|
void update() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
|
void set_led_drive(uint8_t level) { this->led_drive_ = level; }
|
||||||
|
void set_proximity_gain(uint8_t gain) { this->proximity_gain_ = gain; }
|
||||||
|
void set_ambient_gain(uint8_t gain) { this->ambient_gain_ = gain; }
|
||||||
|
void set_gesture_led_drive(uint8_t level) { this->gesture_led_drive_ = level; }
|
||||||
|
void set_gesture_gain(uint8_t gain) { this->gesture_gain_ = gain; }
|
||||||
|
void set_gesture_wait_time(uint8_t wait_time) { this->gesture_wait_time_ = wait_time; }
|
||||||
|
|
||||||
void set_red_channel(sensor::Sensor *red_channel) { red_channel_ = red_channel; }
|
void set_red_channel(sensor::Sensor *red_channel) { red_channel_ = red_channel; }
|
||||||
void set_green_channel(sensor::Sensor *green_channel) { green_channel_ = green_channel; }
|
void set_green_channel(sensor::Sensor *green_channel) { green_channel_ = green_channel; }
|
||||||
void set_blue_channel(sensor::Sensor *blue_channel) { blue_channel_ = blue_channel; }
|
void set_blue_channel(sensor::Sensor *blue_channel) { blue_channel_ = blue_channel; }
|
||||||
@@ -36,6 +43,13 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
|||||||
void report_gesture_(int gesture);
|
void report_gesture_(int gesture);
|
||||||
void process_dataset_(int up, int down, int left, int right);
|
void process_dataset_(int up, int down, int left, int right);
|
||||||
|
|
||||||
|
uint8_t led_drive_;
|
||||||
|
uint8_t proximity_gain_;
|
||||||
|
uint8_t ambient_gain_;
|
||||||
|
uint8_t gesture_led_drive_;
|
||||||
|
uint8_t gesture_gain_;
|
||||||
|
uint8_t gesture_wait_time_;
|
||||||
|
|
||||||
sensor::Sensor *red_channel_{nullptr};
|
sensor::Sensor *red_channel_{nullptr};
|
||||||
sensor::Sensor *green_channel_{nullptr};
|
sensor::Sensor *green_channel_{nullptr};
|
||||||
sensor::Sensor *blue_channel_{nullptr};
|
sensor::Sensor *blue_channel_{nullptr};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import binary_sensor
|
from esphome.components import binary_sensor
|
||||||
from esphome.const import CONF_DIRECTION, CONF_DEVICE_CLASS, DEVICE_CLASS_MOVING
|
from esphome.const import CONF_DIRECTION, DEVICE_CLASS_MOVING
|
||||||
from . import APDS9960, CONF_APDS9960_ID
|
from . import APDS9960, CONF_APDS9960_ID
|
||||||
|
|
||||||
DEPENDENCIES = ["apds9960"]
|
DEPENDENCIES = ["apds9960"]
|
||||||
@@ -13,13 +13,12 @@ DIRECTIONS = {
|
|||||||
"RIGHT": "set_right_direction",
|
"RIGHT": "set_right_direction",
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||||
|
device_class=DEVICE_CLASS_MOVING
|
||||||
|
).extend(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
|
|
||||||
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
||||||
cv.Optional(
|
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
|
||||||
CONF_DEVICE_CLASS, default=DEVICE_CLASS_MOVING
|
|
||||||
): binary_sensor.device_class,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,17 @@ service APIConnection {
|
|||||||
rpc select_command (SelectCommandRequest) returns (void) {}
|
rpc select_command (SelectCommandRequest) returns (void) {}
|
||||||
rpc button_command (ButtonCommandRequest) returns (void) {}
|
rpc button_command (ButtonCommandRequest) returns (void) {}
|
||||||
rpc lock_command (LockCommandRequest) returns (void) {}
|
rpc lock_command (LockCommandRequest) returns (void) {}
|
||||||
|
rpc media_player_command (MediaPlayerCommandRequest) returns (void) {}
|
||||||
|
|
||||||
|
rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
|
||||||
|
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_get_services(BluetoothGATTGetServicesRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_read(BluetoothGATTReadRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_write(BluetoothGATTWriteRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_read_descriptor(BluetoothGATTReadDescriptorRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
|
||||||
|
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
|
||||||
|
rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -76,6 +87,8 @@ message HelloRequest {
|
|||||||
// Not strictly necessary to send but nice for debugging
|
// Not strictly necessary to send but nice for debugging
|
||||||
// purposes.
|
// purposes.
|
||||||
string client_info = 1;
|
string client_info = 1;
|
||||||
|
uint32 api_version_major = 2;
|
||||||
|
uint32 api_version_minor = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirmation of successful connection request.
|
// Confirmation of successful connection request.
|
||||||
@@ -189,6 +202,12 @@ message DeviceInfoResponse {
|
|||||||
string project_version = 9;
|
string project_version = 9;
|
||||||
|
|
||||||
uint32 webserver_port = 10;
|
uint32 webserver_port = 10;
|
||||||
|
|
||||||
|
uint32 bluetooth_proxy_version = 11;
|
||||||
|
|
||||||
|
string manufacturer = 12;
|
||||||
|
|
||||||
|
string friendly_name = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListEntitiesRequest {
|
message ListEntitiesRequest {
|
||||||
@@ -472,6 +491,7 @@ enum SensorStateClass {
|
|||||||
STATE_CLASS_NONE = 0;
|
STATE_CLASS_NONE = 0;
|
||||||
STATE_CLASS_MEASUREMENT = 1;
|
STATE_CLASS_MEASUREMENT = 1;
|
||||||
STATE_CLASS_TOTAL_INCREASING = 2;
|
STATE_CLASS_TOTAL_INCREASING = 2;
|
||||||
|
STATE_CLASS_TOTAL = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SensorLastResetType {
|
enum SensorLastResetType {
|
||||||
@@ -767,6 +787,7 @@ enum ClimateFanMode {
|
|||||||
CLIMATE_FAN_MIDDLE = 6;
|
CLIMATE_FAN_MIDDLE = 6;
|
||||||
CLIMATE_FAN_FOCUS = 7;
|
CLIMATE_FAN_FOCUS = 7;
|
||||||
CLIMATE_FAN_DIFFUSE = 8;
|
CLIMATE_FAN_DIFFUSE = 8;
|
||||||
|
CLIMATE_FAN_QUIET = 9;
|
||||||
}
|
}
|
||||||
enum ClimateSwingMode {
|
enum ClimateSwingMode {
|
||||||
CLIMATE_SWING_OFF = 0;
|
CLIMATE_SWING_OFF = 0;
|
||||||
@@ -897,6 +918,7 @@ message ListEntitiesNumberResponse {
|
|||||||
EntityCategory entity_category = 10;
|
EntityCategory entity_category = 10;
|
||||||
string unit_of_measurement = 11;
|
string unit_of_measurement = 11;
|
||||||
NumberMode mode = 12;
|
NumberMode mode = 12;
|
||||||
|
string device_class = 13;
|
||||||
}
|
}
|
||||||
message NumberStateResponse {
|
message NumberStateResponse {
|
||||||
option (id) = 50;
|
option (id) = 50;
|
||||||
@@ -991,7 +1013,7 @@ message ListEntitiesLockResponse {
|
|||||||
bool supports_open = 9;
|
bool supports_open = 9;
|
||||||
bool requires_code = 10;
|
bool requires_code = 10;
|
||||||
|
|
||||||
# Not yet implemented:
|
// Not yet implemented:
|
||||||
string code_format = 11;
|
string code_format = 11;
|
||||||
}
|
}
|
||||||
message LockStateResponse {
|
message LockStateResponse {
|
||||||
@@ -1010,7 +1032,7 @@ message LockCommandRequest {
|
|||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
LockCommand command = 2;
|
LockCommand command = 2;
|
||||||
|
|
||||||
# Not yet implemented:
|
// Not yet implemented:
|
||||||
bool has_code = 3;
|
bool has_code = 3;
|
||||||
string code = 4;
|
string code = 4;
|
||||||
}
|
}
|
||||||
@@ -1040,3 +1062,279 @@ message ButtonCommandRequest {
|
|||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== MEDIA PLAYER ====================
|
||||||
|
enum MediaPlayerState {
|
||||||
|
MEDIA_PLAYER_STATE_NONE = 0;
|
||||||
|
MEDIA_PLAYER_STATE_IDLE = 1;
|
||||||
|
MEDIA_PLAYER_STATE_PLAYING = 2;
|
||||||
|
MEDIA_PLAYER_STATE_PAUSED = 3;
|
||||||
|
}
|
||||||
|
enum MediaPlayerCommand {
|
||||||
|
MEDIA_PLAYER_COMMAND_PLAY = 0;
|
||||||
|
MEDIA_PLAYER_COMMAND_PAUSE = 1;
|
||||||
|
MEDIA_PLAYER_COMMAND_STOP = 2;
|
||||||
|
MEDIA_PLAYER_COMMAND_MUTE = 3;
|
||||||
|
MEDIA_PLAYER_COMMAND_UNMUTE = 4;
|
||||||
|
}
|
||||||
|
message ListEntitiesMediaPlayerResponse {
|
||||||
|
option (id) = 63;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||||
|
|
||||||
|
string object_id = 1;
|
||||||
|
fixed32 key = 2;
|
||||||
|
string name = 3;
|
||||||
|
string unique_id = 4;
|
||||||
|
|
||||||
|
string icon = 5;
|
||||||
|
bool disabled_by_default = 6;
|
||||||
|
EntityCategory entity_category = 7;
|
||||||
|
|
||||||
|
bool supports_pause = 8;
|
||||||
|
}
|
||||||
|
message MediaPlayerStateResponse {
|
||||||
|
option (id) = 64;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||||
|
option (no_delay) = true;
|
||||||
|
fixed32 key = 1;
|
||||||
|
MediaPlayerState state = 2;
|
||||||
|
float volume = 3;
|
||||||
|
bool muted = 4;
|
||||||
|
}
|
||||||
|
message MediaPlayerCommandRequest {
|
||||||
|
option (id) = 65;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||||
|
option (no_delay) = true;
|
||||||
|
|
||||||
|
fixed32 key = 1;
|
||||||
|
|
||||||
|
bool has_command = 2;
|
||||||
|
MediaPlayerCommand command = 3;
|
||||||
|
|
||||||
|
bool has_volume = 4;
|
||||||
|
float volume = 5;
|
||||||
|
|
||||||
|
bool has_media_url = 6;
|
||||||
|
string media_url = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== BLUETOOTH ====================
|
||||||
|
message SubscribeBluetoothLEAdvertisementsRequest {
|
||||||
|
option (id) = 66;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothServiceData {
|
||||||
|
string uuid = 1;
|
||||||
|
repeated uint32 legacy_data = 2 [deprecated = true];
|
||||||
|
bytes data = 3; // Changed in proto version 1.7
|
||||||
|
}
|
||||||
|
message BluetoothLEAdvertisementResponse {
|
||||||
|
option (id) = 67;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
option (no_delay) = true;
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
string name = 2;
|
||||||
|
sint32 rssi = 3;
|
||||||
|
|
||||||
|
repeated string service_uuids = 4;
|
||||||
|
repeated BluetoothServiceData service_data = 5;
|
||||||
|
repeated BluetoothServiceData manufacturer_data = 6;
|
||||||
|
|
||||||
|
uint32 address_type = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BluetoothDeviceRequestType {
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothDeviceRequest {
|
||||||
|
option (id) = 68;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
BluetoothDeviceRequestType request_type = 2;
|
||||||
|
bool has_address_type = 3;
|
||||||
|
uint32 address_type = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothDeviceConnectionResponse {
|
||||||
|
option (id) = 69;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
bool connected = 2;
|
||||||
|
uint32 mtu = 3;
|
||||||
|
int32 error = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTGetServicesRequest {
|
||||||
|
option (id) = 70;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTDescriptor {
|
||||||
|
repeated uint64 uuid = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTCharacteristic {
|
||||||
|
repeated uint64 uuid = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
uint32 properties = 3;
|
||||||
|
repeated BluetoothGATTDescriptor descriptors = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTService {
|
||||||
|
repeated uint64 uuid = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
repeated BluetoothGATTCharacteristic characteristics = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTGetServicesResponse {
|
||||||
|
option (id) = 71;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
repeated BluetoothGATTService services = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTGetServicesDoneResponse {
|
||||||
|
option (id) = 72;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTReadRequest {
|
||||||
|
option (id) = 73;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTReadResponse {
|
||||||
|
option (id) = 74;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
|
||||||
|
bytes data = 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTWriteRequest {
|
||||||
|
option (id) = 75;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
bool response = 3;
|
||||||
|
|
||||||
|
bytes data = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTReadDescriptorRequest {
|
||||||
|
option (id) = 76;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTWriteDescriptorRequest {
|
||||||
|
option (id) = 77;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
|
||||||
|
bytes data = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTNotifyRequest {
|
||||||
|
option (id) = 78;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
bool enable = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTNotifyDataResponse {
|
||||||
|
option (id) = 79;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
|
||||||
|
bytes data = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribeBluetoothConnectionsFreeRequest {
|
||||||
|
option (id) = 80;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothConnectionsFreeResponse {
|
||||||
|
option (id) = 81;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint32 free = 1;
|
||||||
|
uint32 limit = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTErrorResponse {
|
||||||
|
option (id) = 82;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
int32 error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTWriteResponse {
|
||||||
|
option (id) = 83;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothGATTNotifyResponse {
|
||||||
|
option (id) = 84;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
uint32 handle = 2;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "api_connection.h"
|
#include "api_connection.h"
|
||||||
#include "esphome/core/entity_base.h"
|
|
||||||
#include "esphome/core/log.h"
|
|
||||||
#include "esphome/components/network/util.h"
|
|
||||||
#include "esphome/core/version.h"
|
|
||||||
#include "esphome/core/hal.h"
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include "esphome/components/network/util.h"
|
||||||
|
#include "esphome/core/entity_base.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/version.h"
|
||||||
|
|
||||||
#ifdef USE_DEEP_SLEEP
|
#ifdef USE_DEEP_SLEEP
|
||||||
#include "esphome/components/deep_sleep/deep_sleep_component.h"
|
#include "esphome/components/deep_sleep/deep_sleep_component.h"
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
#ifdef USE_HOMEASSISTANT_TIME
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
#include "esphome/components/homeassistant/time/homeassistant_time.h"
|
#include "esphome/components/homeassistant/time/homeassistant_time.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_FAN
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
#include "esphome/components/fan/fan_helpers.h"
|
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -23,7 +23,7 @@ static const char *const TAG = "api.connection";
|
|||||||
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
||||||
|
|
||||||
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
|
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
|
||||||
: parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
|
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
|
||||||
this->proto_write_buffer_.reserve(64);
|
this->proto_write_buffer_.reserve(64);
|
||||||
|
|
||||||
#if defined(USE_API_PLAINTEXT)
|
#if defined(USE_API_PLAINTEXT)
|
||||||
@@ -105,6 +105,7 @@ void APIConnection::loop() {
|
|||||||
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str());
|
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str());
|
||||||
}
|
}
|
||||||
} else if (now - this->last_traffic_ > keepalive) {
|
} else if (now - this->last_traffic_ > keepalive) {
|
||||||
|
ESP_LOGVV(TAG, "Sending keepalive PING...");
|
||||||
this->sent_ping_ = true;
|
this->sent_ping_ = true;
|
||||||
this->send_ping_request(PingRequest());
|
this->send_ping_request(PingRequest());
|
||||||
}
|
}
|
||||||
@@ -252,9 +253,6 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
// Shut-up about usage of deprecated speed_level_to_enum/speed_enum_to_level functions for a bit.
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
bool APIConnection::send_fan_state(fan::Fan *fan) {
|
bool APIConnection::send_fan_state(fan::Fan *fan) {
|
||||||
if (!this->state_subscription_)
|
if (!this->state_subscription_)
|
||||||
return false;
|
return false;
|
||||||
@@ -267,7 +265,6 @@ bool APIConnection::send_fan_state(fan::Fan *fan) {
|
|||||||
resp.oscillating = fan->oscillating;
|
resp.oscillating = fan->oscillating;
|
||||||
if (traits.supports_speed()) {
|
if (traits.supports_speed()) {
|
||||||
resp.speed_level = fan->speed;
|
resp.speed_level = fan->speed;
|
||||||
resp.speed = static_cast<enums::FanSpeed>(fan::speed_level_to_enum(fan->speed, traits.supported_speed_count()));
|
|
||||||
}
|
}
|
||||||
if (traits.supports_direction())
|
if (traits.supports_direction())
|
||||||
resp.direction = static_cast<enums::FanDirection>(fan->direction);
|
resp.direction = static_cast<enums::FanDirection>(fan->direction);
|
||||||
@@ -294,8 +291,6 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
|
|||||||
if (fan == nullptr)
|
if (fan == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto traits = fan->get_traits();
|
|
||||||
|
|
||||||
auto call = fan->make_call();
|
auto call = fan->make_call();
|
||||||
if (msg.has_state)
|
if (msg.has_state)
|
||||||
call.set_state(msg.state);
|
call.set_state(msg.state);
|
||||||
@@ -304,14 +299,11 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
|
|||||||
if (msg.has_speed_level) {
|
if (msg.has_speed_level) {
|
||||||
// Prefer level
|
// Prefer level
|
||||||
call.set_speed(msg.speed_level);
|
call.set_speed(msg.speed_level);
|
||||||
} else if (msg.has_speed) {
|
|
||||||
call.set_speed(fan::speed_enum_to_level(static_cast<fan::FanSpeed>(msg.speed), traits.supported_speed_count()));
|
|
||||||
}
|
}
|
||||||
if (msg.has_direction)
|
if (msg.has_direction)
|
||||||
call.set_direction(static_cast<fan::FanDirection>(msg.direction));
|
call.set_direction(static_cast<fan::FanDirection>(msg.direction));
|
||||||
call.perform();
|
call.perform();
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
@@ -624,6 +616,7 @@ bool APIConnection::send_number_info(number::Number *number) {
|
|||||||
msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
|
msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
|
||||||
msg.unit_of_measurement = number->traits.get_unit_of_measurement();
|
msg.unit_of_measurement = number->traits.get_unit_of_measurement();
|
||||||
msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
|
msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
|
||||||
|
msg.device_class = number->traits.get_device_class();
|
||||||
|
|
||||||
msg.min_value = number->traits.get_min_value();
|
msg.min_value = number->traits.get_min_value();
|
||||||
msg.max_value = number->traits.get_max_value();
|
msg.max_value = number->traits.get_max_value();
|
||||||
@@ -744,6 +737,52 @@ void APIConnection::lock_command(const LockCommandRequest &msg) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
|
||||||
|
if (!this->state_subscription_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MediaPlayerStateResponse resp{};
|
||||||
|
resp.key = media_player->get_object_id_hash();
|
||||||
|
resp.state = static_cast<enums::MediaPlayerState>(media_player->state);
|
||||||
|
resp.volume = media_player->volume;
|
||||||
|
resp.muted = media_player->is_muted();
|
||||||
|
return this->send_media_player_state_response(resp);
|
||||||
|
}
|
||||||
|
bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
|
||||||
|
ListEntitiesMediaPlayerResponse msg;
|
||||||
|
msg.key = media_player->get_object_id_hash();
|
||||||
|
msg.object_id = media_player->get_object_id();
|
||||||
|
msg.name = media_player->get_name();
|
||||||
|
msg.unique_id = get_default_unique_id("media_player", media_player);
|
||||||
|
msg.icon = media_player->get_icon();
|
||||||
|
msg.disabled_by_default = media_player->is_disabled_by_default();
|
||||||
|
msg.entity_category = static_cast<enums::EntityCategory>(media_player->get_entity_category());
|
||||||
|
|
||||||
|
auto traits = media_player->get_traits();
|
||||||
|
msg.supports_pause = traits.get_supports_pause();
|
||||||
|
|
||||||
|
return this->send_list_entities_media_player_response(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
|
||||||
|
media_player::MediaPlayer *media_player = App.get_media_player_by_key(msg.key);
|
||||||
|
if (media_player == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto call = media_player->make_call();
|
||||||
|
if (msg.has_command) {
|
||||||
|
call.set_command(static_cast<media_player::MediaPlayerCommand>(msg.command));
|
||||||
|
}
|
||||||
|
if (msg.has_volume) {
|
||||||
|
call.set_volume(msg.volume);
|
||||||
|
}
|
||||||
|
if (msg.has_media_url) {
|
||||||
|
call.set_media_url(msg.media_url);
|
||||||
|
}
|
||||||
|
call.perform();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
|
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
|
||||||
if (!this->state_subscription_)
|
if (!this->state_subscription_)
|
||||||
@@ -788,6 +827,56 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
|
bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg) {
|
||||||
|
if (!this->bluetooth_le_advertisement_subscription_)
|
||||||
|
return false;
|
||||||
|
if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) {
|
||||||
|
BluetoothLEAdvertisementResponse resp = msg;
|
||||||
|
for (auto &service : resp.service_data) {
|
||||||
|
service.legacy_data.assign(service.data.begin(), service.data.end());
|
||||||
|
service.data.clear();
|
||||||
|
}
|
||||||
|
for (auto &manufacturer_data : resp.manufacturer_data) {
|
||||||
|
manufacturer_data.legacy_data.assign(manufacturer_data.data.begin(), manufacturer_data.data.end());
|
||||||
|
manufacturer_data.data.clear();
|
||||||
|
}
|
||||||
|
return this->send_bluetooth_le_advertisement_response(resp);
|
||||||
|
}
|
||||||
|
return this->send_bluetooth_le_advertisement_response(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_device_request(const BluetoothDeviceRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_device_request(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_read(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_write(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_read_descriptor(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_write_descriptor(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_send_services(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIConnection::bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) {
|
||||||
|
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_notify(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_free(
|
||||||
|
const SubscribeBluetoothConnectionsFreeRequest &msg) {
|
||||||
|
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 resp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
|
bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
|
||||||
if (this->log_subscription_ < level)
|
if (this->log_subscription_ < level)
|
||||||
return false;
|
return false;
|
||||||
@@ -805,11 +894,14 @@ bool APIConnection::send_log_message(int level, const char *tag, const char *lin
|
|||||||
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
||||||
this->client_info_ = msg.client_info + " (" + this->helper_->getpeername() + ")";
|
this->client_info_ = msg.client_info + " (" + this->helper_->getpeername() + ")";
|
||||||
this->helper_->set_log_info(client_info_);
|
this->helper_->set_log_info(client_info_);
|
||||||
ESP_LOGV(TAG, "Hello from client: '%s'", this->client_info_.c_str());
|
this->client_api_version_major_ = msg.api_version_major;
|
||||||
|
this->client_api_version_minor_ = msg.api_version_minor;
|
||||||
|
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(),
|
||||||
|
this->client_api_version_major_, this->client_api_version_minor_);
|
||||||
|
|
||||||
HelloResponse resp;
|
HelloResponse resp;
|
||||||
resp.api_version_major = 1;
|
resp.api_version_major = 1;
|
||||||
resp.api_version_minor = 6;
|
resp.api_version_minor = 7;
|
||||||
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
|
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
|
||||||
resp.name = App.get_name();
|
resp.name = App.get_name();
|
||||||
|
|
||||||
@@ -838,9 +930,15 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
|||||||
DeviceInfoResponse resp{};
|
DeviceInfoResponse resp{};
|
||||||
resp.uses_password = this->parent_->uses_password();
|
resp.uses_password = this->parent_->uses_password();
|
||||||
resp.name = App.get_name();
|
resp.name = App.get_name();
|
||||||
|
resp.friendly_name = App.get_friendly_name();
|
||||||
resp.mac_address = get_mac_address_pretty();
|
resp.mac_address = get_mac_address_pretty();
|
||||||
resp.esphome_version = ESPHOME_VERSION;
|
resp.esphome_version = ESPHOME_VERSION;
|
||||||
resp.compilation_time = App.get_compilation_time();
|
resp.compilation_time = App.get_compilation_time();
|
||||||
|
#if defined(USE_ESP8266) || defined(USE_ESP32)
|
||||||
|
resp.manufacturer = "Espressif";
|
||||||
|
#elif defined(USE_RP2040)
|
||||||
|
resp.manufacturer = "Raspberry Pi";
|
||||||
|
#endif
|
||||||
resp.model = ESPHOME_BOARD;
|
resp.model = ESPHOME_BOARD;
|
||||||
#ifdef USE_DEEP_SLEEP
|
#ifdef USE_DEEP_SLEEP
|
||||||
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
|
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
|
||||||
@@ -851,6 +949,9 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
resp.webserver_port = USE_WEBSERVER_PORT;
|
resp.webserver_port = USE_WEBSERVER_PORT;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
|
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
|
||||||
#endif
|
#endif
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
@@ -908,7 +1009,7 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this->last_traffic_ = millis();
|
// Do not set last_traffic_ on send
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void APIConnection::on_unauthenticated_access() {
|
void APIConnection::on_unauthenticated_access() {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "api_frame_helper.h"
|
||||||
#include "esphome/core/application.h"
|
|
||||||
#include "api_pb2.h"
|
#include "api_pb2.h"
|
||||||
#include "api_pb2_service.h"
|
#include "api_pb2_service.h"
|
||||||
#include "api_server.h"
|
#include "api_server.h"
|
||||||
#include "api_frame_helper.h"
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
@@ -82,6 +84,11 @@ class APIConnection : public APIServerConnection {
|
|||||||
bool send_lock_state(lock::Lock *a_lock, lock::LockState state);
|
bool send_lock_state(lock::Lock *a_lock, lock::LockState state);
|
||||||
bool send_lock_info(lock::Lock *a_lock);
|
bool send_lock_info(lock::Lock *a_lock);
|
||||||
void lock_command(const LockCommandRequest &msg) override;
|
void lock_command(const LockCommandRequest &msg) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
bool send_media_player_state(media_player::MediaPlayer *media_player);
|
||||||
|
bool send_media_player_info(media_player::MediaPlayer *media_player);
|
||||||
|
void media_player_command(const MediaPlayerCommandRequest &msg) override;
|
||||||
#endif
|
#endif
|
||||||
bool send_log_message(int level, const char *tag, const char *line);
|
bool send_log_message(int level, const char *tag, const char *line);
|
||||||
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
||||||
@@ -89,6 +96,20 @@ class APIConnection : public APIServerConnection {
|
|||||||
return;
|
return;
|
||||||
this->send_homeassistant_service_response(call);
|
this->send_homeassistant_service_response(call);
|
||||||
}
|
}
|
||||||
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
|
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg);
|
||||||
|
|
||||||
|
void bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
|
||||||
|
void bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) override;
|
||||||
|
void bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) override;
|
||||||
|
void bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) override;
|
||||||
|
void bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) override;
|
||||||
|
void bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) override;
|
||||||
|
void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) override;
|
||||||
|
BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
|
||||||
|
const SubscribeBluetoothConnectionsFreeRequest &msg) override;
|
||||||
|
|
||||||
|
#endif
|
||||||
#ifdef USE_HOMEASSISTANT_TIME
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
void send_time_request() {
|
void send_time_request() {
|
||||||
GetTimeRequest req;
|
GetTimeRequest req;
|
||||||
@@ -129,6 +150,9 @@ class APIConnection : public APIServerConnection {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
void execute_service(const ExecuteServiceRequest &msg) override;
|
void execute_service(const ExecuteServiceRequest &msg) override;
|
||||||
|
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
|
||||||
|
this->bluetooth_le_advertisement_subscription_ = true;
|
||||||
|
}
|
||||||
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
|
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
|
||||||
bool is_connection_setup() override {
|
bool is_connection_setup() override {
|
||||||
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated();
|
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated();
|
||||||
@@ -162,6 +186,8 @@ class APIConnection : public APIServerConnection {
|
|||||||
std::unique_ptr<APIFrameHelper> helper_;
|
std::unique_ptr<APIFrameHelper> helper_;
|
||||||
|
|
||||||
std::string client_info_;
|
std::string client_info_;
|
||||||
|
uint32_t client_api_version_major_{0};
|
||||||
|
uint32_t client_api_version_minor_{0};
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
esp32_camera::CameraImageReader image_reader_;
|
esp32_camera::CameraImageReader image_reader_;
|
||||||
#endif
|
#endif
|
||||||
@@ -171,6 +197,7 @@ class APIConnection : public APIServerConnection {
|
|||||||
uint32_t last_traffic_;
|
uint32_t last_traffic_;
|
||||||
bool sent_ping_{false};
|
bool sent_ping_{false};
|
||||||
bool service_call_subscription_{false};
|
bool service_call_subscription_{false};
|
||||||
|
bool bluetooth_le_advertisement_subscription_{false};
|
||||||
bool next_close_ = false;
|
bool next_close_ = false;
|
||||||
APIServer *parent_;
|
APIServer *parent_;
|
||||||
InitialStateIterator initial_state_iterator_;
|
InitialStateIterator initial_state_iterator_;
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
|
|||||||
*
|
*
|
||||||
* If the handshake is still active when this method returns and a read/write can't take place at
|
* If the handshake is still active when this method returns and a read/write can't take place at
|
||||||
* the moment, returns WOULD_BLOCK.
|
* the moment, returns WOULD_BLOCK.
|
||||||
* If an error occured, returns that error. Only returns OK if the transport is ready for data
|
* If an error occurred, returns that error. Only returns OK if the transport is ready for data
|
||||||
* traffic.
|
* traffic.
|
||||||
*/
|
*/
|
||||||
APIError APINoiseFrameHelper::state_action_() {
|
APIError APINoiseFrameHelper::state_action_() {
|
||||||
@@ -586,7 +586,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
|
|||||||
}
|
}
|
||||||
return APIError::OK;
|
return APIError::OK;
|
||||||
} else if (sent == -1) {
|
} else if (sent == -1) {
|
||||||
// an error occured
|
// an error occurred
|
||||||
state_ = State::FAILED;
|
state_ = State::FAILED;
|
||||||
HELPER_LOG("Socket write failed with errno %d", errno);
|
HELPER_LOG("Socket write failed with errno %d", errno);
|
||||||
return APIError::SOCKET_WRITE_FAILED;
|
return APIError::SOCKET_WRITE_FAILED;
|
||||||
@@ -616,6 +616,9 @@ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
|
|||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
iov[0].iov_base = header;
|
iov[0].iov_base = header;
|
||||||
iov[0].iov_len = 3;
|
iov[0].iov_len = 3;
|
||||||
|
if (len == 0) {
|
||||||
|
return write_raw_(iov, 1);
|
||||||
|
}
|
||||||
iov[1].iov_base = const_cast<uint8_t *>(data);
|
iov[1].iov_base = const_cast<uint8_t *>(data);
|
||||||
iov[1].iov_len = len;
|
iov[1].iov_len = len;
|
||||||
|
|
||||||
@@ -913,6 +916,9 @@ APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *pay
|
|||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
iov[0].iov_base = &header[0];
|
iov[0].iov_base = &header[0];
|
||||||
iov[0].iov_len = header.size();
|
iov[0].iov_len = header.size();
|
||||||
|
if (payload_len == 0) {
|
||||||
|
return write_raw_(iov, 1);
|
||||||
|
}
|
||||||
iov[1].iov_base = const_cast<uint8_t *>(payload);
|
iov[1].iov_base = const_cast<uint8_t *>(payload);
|
||||||
iov[1].iov_len = payload_len;
|
iov[1].iov_len = payload_len;
|
||||||
|
|
||||||
@@ -980,7 +986,7 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt
|
|||||||
}
|
}
|
||||||
return APIError::OK;
|
return APIError::OK;
|
||||||
} else if (sent == -1) {
|
} else if (sent == -1) {
|
||||||
// an error occured
|
// an error occurred
|
||||||
state_ = State::FAILED;
|
state_ = State::FAILED;
|
||||||
HELPER_LOG("Socket write failed with errno %d", errno);
|
HELPER_LOG("Socket write failed with errno %d", errno);
|
||||||
return APIError::SOCKET_WRITE_FAILED;
|
return APIError::SOCKET_WRITE_FAILED;
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ class APINoiseFrameHelper : public APIFrameHelper {
|
|||||||
std::vector<uint8_t> prologue_;
|
std::vector<uint8_t> prologue_;
|
||||||
|
|
||||||
std::shared_ptr<APINoiseContext> ctx_;
|
std::shared_ptr<APINoiseContext> ctx_;
|
||||||
NoiseHandshakeState *handshake_ = nullptr;
|
NoiseHandshakeState *handshake_{nullptr};
|
||||||
NoiseCipherState *send_cipher_ = nullptr;
|
NoiseCipherState *send_cipher_{nullptr};
|
||||||
NoiseCipherState *recv_cipher_ = nullptr;
|
NoiseCipherState *recv_cipher_{nullptr};
|
||||||
NoiseProtocolId nid_;
|
NoiseProtocolId nid_;
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user