mirror of
https://github.com/esphome/esphome.git
synced 2025-11-09 11:31:50 +00:00
Compare commits
767 Commits
2022.8.2
...
2023.4.0b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fbbcd6d8a | ||
|
|
1a86167a47 | ||
|
|
614ed7fd0c | ||
|
|
4eb69d6af5 | ||
|
|
0547f2a931 | ||
|
|
b5fbe0b145 | ||
|
|
443c3c2a56 | ||
|
|
d75daa9644 | ||
|
|
7963abb27a | ||
|
|
0b9e8fda34 | ||
|
|
a3cacc0c8b | ||
|
|
5a4840f641 | ||
|
|
3d7d689040 | ||
|
|
b60c08dd28 | ||
|
|
80bc567c31 | ||
|
|
888ac2e180 | ||
|
|
421ebcc8b2 | ||
|
|
b56fa8c50a | ||
|
|
42401775e1 | ||
|
|
9c9bc58c16 | ||
|
|
fbc129cccc | ||
|
|
99638190cb | ||
|
|
d78e9e6aa8 | ||
|
|
878155a03d | ||
|
|
9922eb83e2 | ||
|
|
79f861f012 | ||
|
|
4faa9d109e | ||
|
|
28534ecc61 | ||
|
|
616e0a21d8 | ||
|
|
a546ffd490 | ||
|
|
b5d0aede38 | ||
|
|
a014d853a4 | ||
|
|
c4ddf7697d | ||
|
|
a2931b6774 | ||
|
|
3ac7bf3761 | ||
|
|
922344811f | ||
|
|
cb2fcaa9b1 | ||
|
|
1f50bd0649 | ||
|
|
06f83bf1c0 | ||
|
|
c2756d57d8 | ||
|
|
56504692af | ||
|
|
e542e75b9e | ||
|
|
806e43c34c | ||
|
|
29e7d00894 | ||
|
|
9ee661c1e4 | ||
|
|
36c0e2416d | ||
|
|
e4ba3ff1db | ||
|
|
be69b49880 | ||
|
|
cc317d27f5 | ||
|
|
c16709ed95 | ||
|
|
e13eaf6706 | ||
|
|
a1eb3b8475 | ||
|
|
d52e425ba2 | ||
|
|
d70e7da0ef | ||
|
|
d42f35de5d | ||
|
|
cd57469e06 | ||
|
|
d98d6ff45f | ||
|
|
14e38f0469 | ||
|
|
f0f6d3f1cd | ||
|
|
0b383542da | ||
|
|
b2cec10601 | ||
|
|
48658d5a55 | ||
|
|
5207ca1d52 | ||
|
|
7196fb8e82 | ||
|
|
48ada2eebb | ||
|
|
0de5808ed2 | ||
|
|
ebc544e4b4 | ||
|
|
a31fb3c987 | ||
|
|
dfc7cd7f5d | ||
|
|
a8bb2a42a1 | ||
|
|
3d4c0e6667 | ||
|
|
25fb288016 | ||
|
|
1b8b8cdd11 | ||
|
|
c298c1166f | ||
|
|
c3d9eef01f | ||
|
|
5ffdc66864 | ||
|
|
2f50e18eb5 | ||
|
|
9922c1503a | ||
|
|
fce99d4b17 | ||
|
|
11567085d8 | ||
|
|
83f8e84247 | ||
|
|
215107e8ea | ||
|
|
d3f2b93c42 | ||
|
|
11eb5cb0fa | ||
|
|
9a7af97b2d | ||
|
|
5e11469f50 | ||
|
|
0c7a3d1fff | ||
|
|
8a705bf4b0 | ||
|
|
ee7102fcd1 | ||
|
|
a44e38300b | ||
|
|
b00e20c29f | ||
|
|
6a89180deb | ||
|
|
65d2b806cc | ||
|
|
c149a3033c | ||
|
|
4b7c233f1a | ||
|
|
6e8e9c2aa9 | ||
|
|
b6f628ee40 | ||
|
|
bf79a700b7 | ||
|
|
cdeb6e750f | ||
|
|
d642aeba0f | ||
|
|
6a6aee510d | ||
|
|
ea17a92dbc | ||
|
|
32a0a60480 | ||
|
|
5a56644702 | ||
|
|
29113808ee | ||
|
|
dd226360bb | ||
|
|
1a9aedf152 | ||
|
|
d82c6df57e | ||
|
|
7c91b4474a | ||
|
|
a4f21db272 | ||
|
|
58a8e1859e | ||
|
|
2bed5b18c1 | ||
|
|
fb5eb57345 | ||
|
|
6471361715 | ||
|
|
01687a9d57 | ||
|
|
801fbf44c5 | ||
|
|
ba1416cc0e | ||
|
|
afc1c83af4 | ||
|
|
da056866ff | ||
|
|
336c2d34e6 | ||
|
|
f3a969d35c | ||
|
|
63db42a1d4 | ||
|
|
c12dd77c64 | ||
|
|
f58ffe41f8 | ||
|
|
4f138c600b | ||
|
|
445d2e372c | ||
|
|
1087cb55b4 | ||
|
|
600f4be2c4 | ||
|
|
5e6665494d | ||
|
|
2ef25f3153 | ||
|
|
bc28ea1fde | ||
|
|
623e31ddee | ||
|
|
ceebe14628 | ||
|
|
b29cc58144 | ||
|
|
1b328da265 | ||
|
|
06ca5354b2 | ||
|
|
356efdb92c | ||
|
|
bb5ab8b36d | ||
|
|
6ecf4ecac6 | ||
|
|
05ab49a615 | ||
|
|
3773c385c7 | ||
|
|
3227ef4bca | ||
|
|
5a07e8d32b | ||
|
|
29571a1acd | ||
|
|
b8538c2c12 | ||
|
|
7466773ac8 | ||
|
|
b8ca40170e | ||
|
|
bd86a0ac3b | ||
|
|
df3f13ded8 | ||
|
|
a428e2b689 | ||
|
|
86407b9f6f | ||
|
|
eceb79ceab | ||
|
|
43fb68f8a0 | ||
|
|
14e7b8a1ef | ||
|
|
62459a8ae1 | ||
|
|
86c0e6114f | ||
|
|
1a9141877d | ||
|
|
6ec18fc630 | ||
|
|
4d674392e8 | ||
|
|
6704b2cedf | ||
|
|
fe4fb5f1ac | ||
|
|
350d4e5071 | ||
|
|
23f47d0ad2 | ||
|
|
f98d93efa8 | ||
|
|
91e037346b | ||
|
|
8e1430243e | ||
|
|
98b3d294aa | ||
|
|
38a01988a5 | ||
|
|
d16eff5039 | ||
|
|
8fb481751f | ||
|
|
ba6f89a757 | ||
|
|
48e76e1538 | ||
|
|
0e1d018ce3 | ||
|
|
50fbbf2d3b | ||
|
|
247916fe89 | ||
|
|
ed801f7a27 | ||
|
|
f68d577986 | ||
|
|
5c49730cb9 | ||
|
|
04c12823b5 | ||
|
|
add40c7652 | ||
|
|
72391389a3 | ||
|
|
e68beb8a43 | ||
|
|
40e2832e67 | ||
|
|
36a1f6cfb1 | ||
|
|
12bef16d54 | ||
|
|
77db8c8401 | ||
|
|
66eecd3675 | ||
|
|
c03b1fae68 | ||
|
|
37d55b55fc | ||
|
|
9aed758d1b | ||
|
|
dbe5587806 | ||
|
|
30eec5adee | ||
|
|
5307dfee21 | ||
|
|
8b5b9e508b | ||
|
|
7665e9b076 | ||
|
|
227d94f38d | ||
|
|
b724ae9e0e | ||
|
|
df6cc14201 | ||
|
|
d981d7859d | ||
|
|
0f1ec515c1 | ||
|
|
78e18256f7 | ||
|
|
a0d04ba091 | ||
|
|
c02871fdfe | ||
|
|
0d52f555b2 | ||
|
|
025cf6320f | ||
|
|
5997401e9e | ||
|
|
b4068dac56 | ||
|
|
458d6e24fc | ||
|
|
4f4ca61ada | ||
|
|
dfeeccfcca | ||
|
|
3a101e8ec5 | ||
|
|
7a2d7fdd19 | ||
|
|
4899dfe642 | ||
|
|
78f5c417a4 | ||
|
|
b8c0f88440 | ||
|
|
d6b6e94059 | ||
|
|
310355a00b | ||
|
|
8cf26d6f3c | ||
|
|
b15a10f905 | ||
|
|
58eeb6b1b8 | ||
|
|
f8acc45be4 | ||
|
|
b7ab00b699 | ||
|
|
045489e6d7 | ||
|
|
b14e774a27 | ||
|
|
2a8745d7e0 | ||
|
|
499cb615f1 | ||
|
|
5dcf1debd7 | ||
|
|
9b57e1ac1d | ||
|
|
68683e3a50 | ||
|
|
4d192c7387 | ||
|
|
d83324c4dc | ||
|
|
ecde4c1d2d | ||
|
|
bd8e470726 | ||
|
|
9dd01b30bd | ||
|
|
d2913fe627 | ||
|
|
881cd535b9 | ||
|
|
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 | ||
|
|
034b47c23a | ||
|
|
3e017efa30 | ||
|
|
aca56fcdcc | ||
|
|
e778a445d9 | ||
|
|
ded86493c2 | ||
|
|
4d72eb42a5 | ||
|
|
267f0587c6 | ||
|
|
4a374a466a | ||
|
|
b27a328d1e | ||
|
|
d94e9d92ca | ||
|
|
36c2e770bf | ||
|
|
79040c116d | ||
|
|
4aac76c549 | ||
|
|
0ea97df1af | ||
|
|
92e66a2764 | ||
|
|
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 | ||
|
|
0d50caa179 | ||
|
|
8b06135b41 | ||
|
|
573ea55187 | ||
|
|
b48b5d6cc7 | ||
|
|
39af967433 | ||
|
|
83b5e01a28 | ||
|
|
1eacbd50fa | ||
|
|
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 | ||
|
|
dbbbba3cf8 | ||
|
|
16e523ca68 | ||
|
|
3b2bbd306f | ||
|
|
54caed36f7 | ||
|
|
dfcccda69e | ||
|
|
de352c1609 | ||
|
|
c30068fc97 | ||
|
|
f28f712827 | ||
|
|
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 | ||
|
|
555bba7698 | ||
|
|
294901fbe9 | ||
|
|
ec576bf9f9 | ||
|
|
9273e3775b | ||
|
|
ce5cedb466 | ||
|
|
b184b01600 | ||
|
|
81b4078871 | ||
|
|
d067c8f80b | ||
|
|
8975b4b3f6 | ||
|
|
20da03f8c6 | ||
|
|
ef26677b67 | ||
|
|
91925b1826 | ||
|
|
1f33ad037d | ||
|
|
fef60e335e | ||
|
|
195c78846f | ||
|
|
0f9c956c04 | ||
|
|
7258a82875 | ||
|
|
c1f696c32a | ||
|
|
f2b63d9c67 | ||
|
|
7896a7783b | ||
|
|
621771e1ee | ||
|
|
2b032e8606 | ||
|
|
5e1b724697 | ||
|
|
e6db61c2f0 | ||
|
|
c2e198311c | ||
|
|
d874626662 | ||
|
|
eead72333e | ||
|
|
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 | ||
|
|
c317422ed7 | ||
|
|
614eb81ad7 | ||
|
|
219c5953f1 | ||
|
|
5d712c73ea | ||
|
|
7097b7677e | ||
|
|
7a4cf13e0c | ||
|
|
4788a6182e | ||
|
|
e3dad7c632 | ||
|
|
1b4156646e | ||
|
|
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 | ||
|
|
43539f2dbf | ||
|
|
df6830110d | ||
|
|
1a524a5a50 | ||
|
|
1a2288cccf | ||
|
|
8df27d4c3f | ||
|
|
0688deca6b | ||
|
|
01a4443b6c | ||
|
|
e008b054cb | ||
|
|
1cf213dad8 | ||
|
|
aeb81e547b | ||
|
|
479f7703a2 | ||
|
|
c7dc396b6d | ||
|
|
80e3030811 |
@@ -1,15 +1,20 @@
|
|||||||
{
|
{
|
||||||
"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"
|
||||||
],
|
],
|
||||||
|
"containerEnv": {
|
||||||
|
"DEVCONTAINER": "1"
|
||||||
|
},
|
||||||
"runArgs": [
|
"runArgs": [
|
||||||
"--privileged",
|
"--privileged",
|
||||||
"-e",
|
"-e",
|
||||||
"ESPHOME_DASHBOARD_USE_PING=1"
|
"ESPHOME_DASHBOARD_USE_PING=1"
|
||||||
],
|
],
|
||||||
"appPort": 6052,
|
"appPort": 6052,
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
// python
|
// python
|
||||||
"ms-python.python",
|
"ms-python.python",
|
||||||
@@ -51,6 +56,8 @@
|
|||||||
"files.associations": {
|
"files.associations": {
|
||||||
"**/.vscode/*.json": "jsonc"
|
"**/.vscode/*.json": "jsonc"
|
||||||
},
|
},
|
||||||
"C_Cpp.clang_format_path": "/usr/bin/clang-format-11",
|
"C_Cpp.clang_format_path": "/usr/bin/clang-format-13"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.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,7 +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.
|
||||||
|
|||||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.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`:
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -1,13 +1,14 @@
|
|||||||
|
---
|
||||||
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"
|
- package-ecosystem: github-actions
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
|
|||||||
26
.github/workflows/ci-docker.yml
vendored
26
.github/workflows/ci-docker.yml
vendored
@@ -1,31 +1,39 @@
|
|||||||
|
---
|
||||||
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
|
||||||
packages: read
|
packages: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
# yamllint disable-line rule:line-length
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-docker:
|
check-docker:
|
||||||
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"]
|
||||||
@@ -34,7 +42,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
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@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
|
|||||||
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
@@ -1,15 +1,19 @@
|
|||||||
|
---
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [dev, beta, release]
|
branches: [dev, beta, release]
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
|
||||||
permissions:
|
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
|
||||||
|
|
||||||
@@ -37,6 +41,10 @@ jobs:
|
|||||||
file: tests/test3.yaml
|
file: tests/test3.yaml
|
||||||
name: Test tests/test3.yaml
|
name: Test tests/test3.yaml
|
||||||
pio_cache_key: test3
|
pio_cache_key: test3
|
||||||
|
- id: test
|
||||||
|
file: tests/test3.1.yaml
|
||||||
|
name: Test tests/test3.1.yaml
|
||||||
|
pio_cache_key: test3.1
|
||||||
- id: test
|
- id: test
|
||||||
file: tests/test4.yaml
|
file: tests/test4.yaml
|
||||||
name: Test tests/test4.yaml
|
name: Test tests/test4.yaml
|
||||||
@@ -45,6 +53,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,6 +89,8 @@ 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@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -80,17 +98,19 @@ jobs:
|
|||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Cache virtualenv
|
- name: Cache virtualenv
|
||||||
uses: actions/cache@v3
|
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,19 +119,21 @@ 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@v3
|
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'
|
||||||
|
|
||||||
- name: Install clang tools
|
- name: Install clang tools
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
clang-format-11 \
|
clang-format-13 \
|
||||||
clang-tidy-11
|
clang-tidy-11
|
||||||
if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format'
|
if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format'
|
||||||
|
|
||||||
@@ -145,8 +167,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 +184,24 @@ 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.4.0
|
||||||
|
|
||||||
- name: Suggested changes
|
- name: Suggested changes
|
||||||
run: script/ci-suggest-changes
|
run: script/ci-suggest-changes
|
||||||
|
# yamllint disable-line rule:line-length
|
||||||
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format' || matrix.id == 'lint-python')
|
if: always() && (matrix.id == 'clang-tidy' || matrix.id == 'clang-format' || matrix.id == 'lint-python')
|
||||||
|
|
||||||
|
ci-status:
|
||||||
|
name: CI Status
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [ci]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Successful deploy
|
||||||
|
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||||
|
run: exit 0
|
||||||
|
- name: Failing deploy
|
||||||
|
if: ${{ contains(needs.*.result, 'failure') }}
|
||||||
|
run: exit 1
|
||||||
|
|||||||
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: ""
|
||||||
|
|||||||
125
.github/workflows/release.yml
vendored
125
.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:
|
||||||
@@ -20,6 +22,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- 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,8 +30,13 @@ 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
|
||||||
echo "::set-output name=tag::${TAG}"
|
fi
|
||||||
|
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
|
||||||
@@ -39,7 +47,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
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,23 +61,36 @@ 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@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
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@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
@@ -88,67 +109,47 @@ jobs:
|
|||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate short tags
|
||||||
|
id: tags
|
||||||
|
run: |
|
||||||
|
docker/generate_tags.py \
|
||||||
|
--tag "${{ needs.init.outputs.tag }}" \
|
||||||
|
--suffix "${{ matrix.image.suffix }}"
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
run: |
|
uses: docker/build-push-action@v3
|
||||||
docker/build.py \
|
|
||||||
--tag "${{ needs.init.outputs.tag }}" \
|
|
||||||
--arch "${{ matrix.arch }}" \
|
|
||||||
--build-type "${{ matrix.build_type }}" \
|
|
||||||
build \
|
|
||||||
--push
|
|
||||||
|
|
||||||
deploy-docker-manifest:
|
|
||||||
if: github.repository == 'esphome/esphome'
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [init, deploy-docker]
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
build_type: ["ha-addon", "docker", "lint"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
with:
|
||||||
python-version: '3.9'
|
context: .
|
||||||
- name: Enable experimental manifest support
|
file: ./docker/Dockerfile
|
||||||
run: |
|
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||||
mkdir -p ~/.docker
|
target: ${{ matrix.image.target }}
|
||||||
echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
|
push: true
|
||||||
|
# yamllint disable rule:line-length
|
||||||
- name: Log in to docker hub
|
cache-from: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }}
|
||||||
uses: docker/login-action@v2
|
cache-to: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }},mode=max
|
||||||
with:
|
# yamllint enable rule:line-length
|
||||||
username: ${{ secrets.DOCKER_USER }}
|
tags: ${{ steps.tags.outputs.tags }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
build-args: |
|
||||||
- name: Log in to the GitHub container registry
|
BASEIMGTYPE=${{ matrix.image.baseimg }}
|
||||||
uses: docker/login-action@v2
|
BUILD_VERSION=${{ needs.init.outputs.tag }}
|
||||||
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@v5
|
- uses: actions/stale@v8
|
||||||
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@v5
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
days-before-pr-stale: -1
|
days-before-pr-stale: -1
|
||||||
days-before-pr-close: -1
|
days-before-pr-close: -1
|
||||||
|
|||||||
60
.github/workflows/sync-device-classes.yml
vendored
Normal file
60
.github/workflows/sync-device-classes.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
name: Synchronise Device Classes from Home Assistant
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '45 6 * * *'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
name: Sync Device Classes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Checkout Home Assistant
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: home-assistant/core
|
||||||
|
path: lib/home-assistant
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: 3.11
|
||||||
|
|
||||||
|
- name: Install Home Assistant
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -e lib/home-assistant
|
||||||
|
|
||||||
|
- name: Sync
|
||||||
|
run: |
|
||||||
|
python ./script/sync-device_class.py
|
||||||
|
|
||||||
|
- name: Get PR template
|
||||||
|
id: pr-template-body
|
||||||
|
run: |
|
||||||
|
body=$(cat .github/PULL_REQUEST_TEMPLATE.md)
|
||||||
|
delimiter="$(openssl rand -hex 8)"
|
||||||
|
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||||
|
echo "$body" >> $GITHUB_OUTPUT
|
||||||
|
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Commit changes
|
||||||
|
uses: peter-evans/create-pull-request@v4
|
||||||
|
with:
|
||||||
|
commit-message: "Synchronise Device Classes from Home Assistant"
|
||||||
|
committer: esphomebot <esphome@nabucasa.com>
|
||||||
|
author: esphomebot <esphome@nabucasa.com>
|
||||||
|
branch: sync/device-classes/
|
||||||
|
branch-suffix: timestamp
|
||||||
|
delete-branch: true
|
||||||
|
title: "Synchronise Device Classes from Home Assistant"
|
||||||
|
body: ${{ steps.pr-template-body.outputs.body }}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -128,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/psf/black
|
||||||
rev: 22.6.0
|
rev: 23.3.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:
|
||||||
@@ -26,7 +27,7 @@ repos:
|
|||||||
- --branch=release
|
- --branch=release
|
||||||
- --branch=beta
|
- --branch=beta
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.37.3
|
rev: v3.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py38-plus]
|
args: [--py39-plus]
|
||||||
|
|||||||
15
.vscode/tasks.json
vendored
15
.vscode/tasks.json
vendored
@@ -2,15 +2,24 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "run",
|
"label": "Run Dashboard",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python3 -m esphome dashboard config/",
|
"command": "${command:python.interpreterPath}",
|
||||||
|
"args": [
|
||||||
|
"-m",
|
||||||
|
"esphome",
|
||||||
|
"dashboard",
|
||||||
|
"config/"
|
||||||
|
],
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "clang-tidy",
|
"label": "clang-tidy",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "./script/clang-tidy",
|
"command": "${command:python.interpreterPath}",
|
||||||
|
"args": [
|
||||||
|
"./script/clang-tidy"
|
||||||
|
],
|
||||||
"problemMatcher": [
|
"problemMatcher": [
|
||||||
{
|
{
|
||||||
"owner": "clang-tidy",
|
"owner": "clang-tidy",
|
||||||
|
|||||||
60
CODEOWNERS
60
CODEOWNERS
@@ -11,8 +11,10 @@ esphome/*.py @esphome/core
|
|||||||
esphome/core/* @esphome/core
|
esphome/core/* @esphome/core
|
||||||
|
|
||||||
# Integrations
|
# Integrations
|
||||||
|
esphome/components/absolute_humidity/* @DAVe3283
|
||||||
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
|
||||||
@@ -23,20 +25,26 @@ 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
|
||||||
|
esphome/components/as7341/* @mrgnr
|
||||||
esphome/components/async_tcp/* @OttoWinter
|
esphome/components/async_tcp/* @OttoWinter
|
||||||
esphome/components/atc_mithermometer/* @ahpohl
|
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/* @jhansche
|
||||||
|
esphome/components/bedjet/climate/* @jhansche
|
||||||
|
esphome/components/bedjet/fan/* @jhansche
|
||||||
esphome/components/bh1750/* @OttoWinter
|
esphome/components/bh1750/* @OttoWinter
|
||||||
esphome/components/binary_sensor/* @esphome/core
|
esphome/components/binary_sensor/* @esphome/core
|
||||||
esphome/components/bl0939/* @ziceva
|
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/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
|
||||||
@@ -54,33 +62,43 @@ 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/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/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/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/feedback/* @ianchi
|
||||||
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
||||||
|
esphome/components/fs3000/* @kahrendt
|
||||||
esphome/components/globals/* @esphome/core
|
esphome/components/globals/* @esphome/core
|
||||||
esphome/components/gpio/* @esphome/core
|
esphome/components/gpio/* @esphome/core
|
||||||
esphome/components/gps/* @coogle
|
esphome/components/gps/* @coogle
|
||||||
esphome/components/graph/* @synco
|
esphome/components/graph/* @synco
|
||||||
esphome/components/growatt_solar/* @leeuwte
|
esphome/components/growatt_solar/* @leeuwte
|
||||||
|
esphome/components/haier/* @Yarikx
|
||||||
esphome/components/havells_solar/* @sourabhjaiswal
|
esphome/components/havells_solar/* @sourabhjaiswal
|
||||||
esphome/components/hbridge/fan/* @WeekendWarrior
|
esphome/components/hbridge/fan/* @WeekendWarrior
|
||||||
esphome/components/hbridge/light/* @DotNetDann
|
esphome/components/hbridge/light/* @DotNetDann
|
||||||
@@ -89,23 +107,35 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal
|
|||||||
esphome/components/homeassistant/* @OttoWinter
|
esphome/components/homeassistant/* @OttoWinter
|
||||||
esphome/components/honeywellabp/* @RubyBailey
|
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/hydreon_rgxx/* @functionpointer
|
||||||
esphome/components/i2c/* @esphome/core
|
esphome/components/i2c/* @esphome/core
|
||||||
esphome/components/i2s_audio/* @jesserockz
|
esphome/components/i2s_audio/* @jesserockz
|
||||||
|
esphome/components/i2s_audio/media_player/* @jesserockz
|
||||||
|
esphome/components/i2s_audio/microphone/* @jesserockz
|
||||||
|
esphome/components/ili9xxx/* @nielsnl68
|
||||||
|
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
|
||||||
esphome/components/inkplate6/* @jesserockz
|
esphome/components/inkplate6/* @jesserockz
|
||||||
esphome/components/integration/* @OttoWinter
|
esphome/components/integration/* @OttoWinter
|
||||||
|
esphome/components/internal_temperature/* @Mat931
|
||||||
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/kuntze/* @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/max31865/* @DAVe3283
|
||||||
esphome/components/max44009/* @berfenger
|
esphome/components/max44009/* @berfenger
|
||||||
esphome/components/max7219digit/* @rspaargaren
|
esphome/components/max7219digit/* @rspaargaren
|
||||||
@@ -121,14 +151,18 @@ esphome/components/mcp2515/* @danielschramm @mvturnho
|
|||||||
esphome/components/mcp3204/* @rsumner
|
esphome/components/mcp3204/* @rsumner
|
||||||
esphome/components/mcp4728/* @berfenger
|
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/media_player/* @jesserockz
|
||||||
|
esphome/components/microphone/* @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
|
||||||
esphome/components/mlx90393/* @functionpointer
|
esphome/components/mlx90393/* @functionpointer
|
||||||
|
esphome/components/mmc5603/* @benhoff
|
||||||
esphome/components/modbus_controller/* @martgras
|
esphome/components/modbus_controller/* @martgras
|
||||||
esphome/components/modbus_controller/binary_sensor/* @martgras
|
esphome/components/modbus_controller/binary_sensor/* @martgras
|
||||||
esphome/components/modbus_controller/number/* @martgras
|
esphome/components/modbus_controller/number/* @martgras
|
||||||
@@ -137,8 +171,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_ble/* @Fabian-Schmidt @spbrogan
|
||||||
esphome/components/mopeka_pro_check/* @spbrogan
|
esphome/components/mopeka_pro_check/* @spbrogan
|
||||||
|
esphome/components/mopeka_std_check/* @Fabian-Schmidt
|
||||||
|
esphome/components/mpl3115a2/* @kbickar
|
||||||
esphome/components/mpu6886/* @fabaff
|
esphome/components/mpu6886/* @fabaff
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/nextion/* @senexcrenshaw
|
esphome/components/nextion/* @senexcrenshaw
|
||||||
@@ -150,6 +186,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
|
||||||
@@ -172,6 +210,8 @@ 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/* @martgras @sjtrny
|
esphome/components/scd4x/* @martgras @sjtrny
|
||||||
@@ -180,6 +220,7 @@ 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/sen21231/* @shreyaskarnik
|
||||||
esphome/components/sen5x/* @martgras
|
esphome/components/sen5x/* @martgras
|
||||||
esphome/components/sensirion_common/* @martgras
|
esphome/components/sensirion_common/* @martgras
|
||||||
esphome/components/sensor/* @esphome/core
|
esphome/components/sensor/* @esphome/core
|
||||||
@@ -188,10 +229,15 @@ esphome/components/sgp4x/* @SenexCrenshaw @martgras
|
|||||||
esphome/components/shelly_dimmer/* @edge90 @rnauber
|
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/sml/* @alengwenus
|
||||||
esphome/components/smt100/* @piechade
|
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/sonoff_d1/* @anatoly-savchenkov
|
||||||
esphome/components/spi/* @esphome/core
|
esphome/components/spi/* @esphome/core
|
||||||
@@ -217,11 +263,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
|
||||||
@@ -236,14 +285,21 @@ 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/voice_assistant/* @jesserockz
|
||||||
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/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/xiaomi_rtcgq02lm/* @jesserockz
|
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
|
||||||
esphome/components/xpt2046/* @numo68
|
esphome/components/xpt2046/* @nielsnl68 @numo68
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -6,17 +6,14 @@
|
|||||||
ARG BASEIMGTYPE=docker
|
ARG BASEIMGTYPE=docker
|
||||||
|
|
||||||
# https://github.com/hassio-addons/addon-debian-base/releases
|
# https://github.com/hassio-addons/addon-debian-base/releases
|
||||||
FROM ghcr.io/hassio-addons/debian-base/amd64:5.3.0 AS base-hassio-amd64
|
FROM ghcr.io/hassio-addons/debian-base:6.2.3 AS base-hassio
|
||||||
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.3.0 AS base-hassio-arm64
|
|
||||||
FROM ghcr.io/hassio-addons/debian-base/armv7:5.3.0 AS base-hassio-armv7
|
|
||||||
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
|
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
|
||||||
FROM debian:bullseye-20220328-slim AS base-docker-amd64
|
FROM debian:bullseye-20230208-slim AS base-docker
|
||||||
FROM debian:bullseye-20220328-slim AS base-docker-arm64
|
|
||||||
FROM debian:bullseye-20220328-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 \
|
||||||
@@ -29,8 +26,8 @@ RUN \
|
|||||||
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+deb11u7 \
|
||||||
openssh-client=1:8.4p1-5 \
|
openssh-client=1:8.4p1-5+deb11u1 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
@@ -42,11 +39,19 @@ 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==6.0.2 \
|
platformio==6.1.6 \
|
||||||
# Change some platformio settings
|
# Change some platformio settings
|
||||||
&& platformio settings set enable_telemetry No \
|
&& platformio settings set enable_telemetry No \
|
||||||
&& platformio settings set check_platformio_interval 1000000 \
|
&& platformio settings set check_platformio_interval 1000000 \
|
||||||
@@ -94,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-light=1.18.0-6.1+deb11u2 \
|
nginx-light=1.18.0-6.1+deb11u3 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
@@ -130,11 +135,11 @@ 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 \
|
||||||
clang-format-11=1:11.0.1-2 \
|
clang-format-13=1:13.0.1-6~deb11u1 \
|
||||||
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+deb11u1 \
|
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 \
|
||||||
|
|||||||
@@ -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,6 +1,8 @@
|
|||||||
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";
|
||||||
add_header X-Robots-Tag none;
|
add_header X-Robots-Tag none;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
access_log off;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
gzip on;
|
gzip on;
|
||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
sendfile on;
|
sendfile on;
|
||||||
server_tokens off;
|
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
|
|
||||||
@@ -4,6 +4,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import re
|
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
|
||||||
@@ -22,6 +23,9 @@ from esphome.const import (
|
|||||||
CONF_ESPHOME,
|
CONF_ESPHOME,
|
||||||
CONF_PLATFORMIO_OPTIONS,
|
CONF_PLATFORMIO_OPTIONS,
|
||||||
CONF_SUBSTITUTIONS,
|
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
|
||||||
@@ -101,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
|
||||||
@@ -119,25 +123,36 @@ def run_miniterm(config, port):
|
|||||||
ser.dtr = False
|
ser.dtr = False
|
||||||
ser.rts = False
|
ser.rts = False
|
||||||
|
|
||||||
|
tries = 0
|
||||||
|
while tries < 5:
|
||||||
|
try:
|
||||||
with ser:
|
with ser:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
raw = ser.readline()
|
raw = ser.readline()
|
||||||
except serial.SerialException:
|
except serial.SerialException:
|
||||||
_LOGGER.error("Serial port closed!")
|
_LOGGER.error("Serial port closed!")
|
||||||
return
|
return 0
|
||||||
line = (
|
line = (
|
||||||
raw.replace(b"\r", b"")
|
raw.replace(b"\r", b"")
|
||||||
.replace(b"\n", b"")
|
.replace(b"\n", b"")
|
||||||
.decode("utf8", "backslashreplace")
|
.decode("utf8", "backslashreplace")
|
||||||
)
|
)
|
||||||
time = datetime.now().time().strftime("[%H:%M:%S]")
|
time_str = datetime.now().time().strftime("[%H:%M:%S]")
|
||||||
message = time + line
|
message = time_str + line
|
||||||
safe_print(message)
|
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
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def wrap_to_code(name, comp):
|
def wrap_to_code(name, comp):
|
||||||
@@ -241,8 +256,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)
|
||||||
|
|
||||||
@@ -258,10 +272,22 @@ 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":
|
||||||
|
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
|
||||||
return upload_using_esptool(config, host)
|
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
|
||||||
|
|
||||||
if CONF_OTA not in config:
|
if CONF_OTA not in config:
|
||||||
@@ -273,6 +299,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)
|
||||||
|
|
||||||
|
|
||||||
@@ -280,8 +308,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
|
||||||
|
|
||||||
@@ -314,7 +341,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
|
||||||
|
|
||||||
|
|
||||||
@@ -640,6 +667,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."
|
||||||
@@ -663,6 +693,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",
|
||||||
|
|||||||
@@ -254,7 +254,11 @@ async def repeat_action_to_code(config, action_id, template_arg, args):
|
|||||||
var = cg.new_Pvariable(action_id, template_arg)
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
|
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
|
||||||
cg.add(var.set_count(count_template))
|
cg.add(var.set_count(count_template))
|
||||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
actions = await build_action_list(
|
||||||
|
config[CONF_THEN],
|
||||||
|
cg.TemplateArguments(cg.uint32, *template_arg.args),
|
||||||
|
[(cg.uint32, "iteration"), *args],
|
||||||
|
)
|
||||||
cg.add(var.add_then(actions))
|
cg.add(var.add_then(actions))
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -46,6 +47,7 @@ from esphome.cpp_helpers import ( # noqa
|
|||||||
build_registry_list,
|
build_registry_list,
|
||||||
extract_registry_entry_config,
|
extract_registry_entry_config,
|
||||||
register_parented,
|
register_parented,
|
||||||
|
past_safe_mode,
|
||||||
)
|
)
|
||||||
from esphome.cpp_types import ( # noqa
|
from esphome.cpp_types import ( # noqa
|
||||||
global_ns,
|
global_ns,
|
||||||
@@ -62,6 +64,7 @@ from esphome.cpp_types import ( # noqa
|
|||||||
uint16,
|
uint16,
|
||||||
uint32,
|
uint32,
|
||||||
uint64,
|
uint64,
|
||||||
|
int16,
|
||||||
int32,
|
int32,
|
||||||
int64,
|
int64,
|
||||||
size_t,
|
size_t,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
1
esphome/components/absolute_humidity/__init__.py
Normal file
1
esphome/components/absolute_humidity/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CODEOWNERS = ["@DAVe3283"]
|
||||||
182
esphome/components/absolute_humidity/absolute_humidity.cpp
Normal file
182
esphome/components/absolute_humidity/absolute_humidity.cpp
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "absolute_humidity.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace absolute_humidity {
|
||||||
|
|
||||||
|
static const char *const TAG = "absolute_humidity.sensor";
|
||||||
|
|
||||||
|
void AbsoluteHumidityComponent::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up absolute humidity '%s'...", this->get_name().c_str());
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
|
||||||
|
this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
|
||||||
|
if (this->temperature_sensor_->has_state()) {
|
||||||
|
this->temperature_callback_(this->temperature_sensor_->get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, " Added callback for relative humidity '%s'", this->humidity_sensor_->get_name().c_str());
|
||||||
|
this->humidity_sensor_->add_on_state_callback([this](float state) { this->humidity_callback_(state); });
|
||||||
|
if (this->humidity_sensor_->has_state()) {
|
||||||
|
this->humidity_callback_(this->humidity_sensor_->get_state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteHumidityComponent::dump_config() {
|
||||||
|
LOG_SENSOR("", "Absolute Humidity", this);
|
||||||
|
|
||||||
|
switch (this->equation_) {
|
||||||
|
case BUCK:
|
||||||
|
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Buck");
|
||||||
|
break;
|
||||||
|
case TETENS:
|
||||||
|
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Tetens");
|
||||||
|
break;
|
||||||
|
case WOBUS:
|
||||||
|
ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Wobus");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGCONFIG(TAG, "Sources");
|
||||||
|
ESP_LOGCONFIG(TAG, " Temperature: '%s'", this->temperature_sensor_->get_name().c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Relative Humidity: '%s'", this->humidity_sensor_->get_name().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
float AbsoluteHumidityComponent::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
void AbsoluteHumidityComponent::loop() {
|
||||||
|
if (!this->next_update_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->next_update_ = false;
|
||||||
|
|
||||||
|
// Ensure we have source data
|
||||||
|
const bool no_temperature = std::isnan(this->temperature_);
|
||||||
|
const bool no_humidity = std::isnan(this->humidity_);
|
||||||
|
if (no_temperature || no_humidity) {
|
||||||
|
if (no_temperature) {
|
||||||
|
ESP_LOGW(TAG, "No valid state from temperature sensor!");
|
||||||
|
}
|
||||||
|
if (no_humidity) {
|
||||||
|
ESP_LOGW(TAG, "No valid state from temperature sensor!");
|
||||||
|
}
|
||||||
|
ESP_LOGW(TAG, "Unable to calculate absolute humidity.");
|
||||||
|
this->publish_state(NAN);
|
||||||
|
this->status_set_warning();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to desired units
|
||||||
|
const float temperature_c = this->temperature_;
|
||||||
|
const float temperature_k = temperature_c + 273.15;
|
||||||
|
const float hr = this->humidity_ / 100;
|
||||||
|
|
||||||
|
// Calculate saturation vapor pressure
|
||||||
|
float es;
|
||||||
|
switch (this->equation_) {
|
||||||
|
case BUCK:
|
||||||
|
es = es_buck(temperature_c);
|
||||||
|
break;
|
||||||
|
case TETENS:
|
||||||
|
es = es_tetens(temperature_c);
|
||||||
|
break;
|
||||||
|
case WOBUS:
|
||||||
|
es = es_wobus(temperature_c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
|
||||||
|
this->publish_state(NAN);
|
||||||
|
this->status_set_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
|
||||||
|
|
||||||
|
// Calculate absolute humidity
|
||||||
|
const float absolute_humidity = vapor_density(es, hr, temperature_k);
|
||||||
|
|
||||||
|
// Publish absolute humidity
|
||||||
|
ESP_LOGD(TAG, "Publishing absolute humidity %f g/m³", absolute_humidity);
|
||||||
|
this->status_clear_warning();
|
||||||
|
this->publish_state(absolute_humidity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buck equation (https://en.wikipedia.org/wiki/Arden_Buck_equation)
|
||||||
|
// More accurate than Tetens in normal meteorologic conditions
|
||||||
|
float AbsoluteHumidityComponent::es_buck(float temperature_c) {
|
||||||
|
float a, b, c, d;
|
||||||
|
if (temperature_c >= 0) {
|
||||||
|
a = 0.61121;
|
||||||
|
b = 18.678;
|
||||||
|
c = 234.5;
|
||||||
|
d = 257.14;
|
||||||
|
} else {
|
||||||
|
a = 0.61115;
|
||||||
|
b = 18.678;
|
||||||
|
c = 233.7;
|
||||||
|
d = 279.82;
|
||||||
|
}
|
||||||
|
return a * expf((b - (temperature_c / c)) * (temperature_c / (d + temperature_c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tetens equation (https://en.wikipedia.org/wiki/Tetens_equation)
|
||||||
|
float AbsoluteHumidityComponent::es_tetens(float temperature_c) {
|
||||||
|
float a, b;
|
||||||
|
if (temperature_c >= 0) {
|
||||||
|
a = 17.27;
|
||||||
|
b = 237.3;
|
||||||
|
} else {
|
||||||
|
a = 21.875;
|
||||||
|
b = 265.5;
|
||||||
|
}
|
||||||
|
return 0.61078 * expf((a * temperature_c) / (temperature_c + b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wobus equation
|
||||||
|
// https://wahiduddin.net/calc/density_altitude.htm
|
||||||
|
// https://wahiduddin.net/calc/density_algorithms.htm
|
||||||
|
// Calculate the saturation vapor pressure (kPa)
|
||||||
|
float AbsoluteHumidityComponent::es_wobus(float t) {
|
||||||
|
// THIS FUNCTION RETURNS THE SATURATION VAPOR PRESSURE ESW (MILLIBARS)
|
||||||
|
// OVER LIQUID WATER GIVEN THE TEMPERATURE T (CELSIUS). THE POLYNOMIAL
|
||||||
|
// APPROXIMATION BELOW IS DUE TO HERMAN WOBUS, A MATHEMATICIAN WHO
|
||||||
|
// WORKED AT THE NAVY WEATHER RESEARCH FACILITY, NORFOLK, VIRGINIA,
|
||||||
|
// BUT WHO IS NOW RETIRED. THE COEFFICIENTS OF THE POLYNOMIAL WERE
|
||||||
|
// CHOSEN TO FIT THE VALUES IN TABLE 94 ON PP. 351-353 OF THE SMITH-
|
||||||
|
// SONIAN METEOROLOGICAL TABLES BY ROLAND LIST (6TH EDITION). THE
|
||||||
|
// APPROXIMATION IS VALID FOR -50 < T < 100C.
|
||||||
|
//
|
||||||
|
// Baker, Schlatter 17-MAY-1982 Original version.
|
||||||
|
|
||||||
|
const float c0 = +0.99999683e00;
|
||||||
|
const float c1 = -0.90826951e-02;
|
||||||
|
const float c2 = +0.78736169e-04;
|
||||||
|
const float c3 = -0.61117958e-06;
|
||||||
|
const float c4 = +0.43884187e-08;
|
||||||
|
const float c5 = -0.29883885e-10;
|
||||||
|
const float c6 = +0.21874425e-12;
|
||||||
|
const float c7 = -0.17892321e-14;
|
||||||
|
const float c8 = +0.11112018e-16;
|
||||||
|
const float c9 = -0.30994571e-19;
|
||||||
|
const float p = c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * (c6 + t * (c7 + t * (c8 + t * (c9)))))))));
|
||||||
|
return 0.61078 / pow(p, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From https://www.environmentalbiophysics.org/chalk-talk-how-to-calculate-absolute-humidity/
|
||||||
|
// H/T to https://esphome.io/cookbook/bme280_environment.html
|
||||||
|
// H/T to https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
|
||||||
|
float AbsoluteHumidityComponent::vapor_density(float es, float hr, float ta) {
|
||||||
|
// es = saturated vapor pressure (kPa)
|
||||||
|
// hr = relative humidity [0-1]
|
||||||
|
// ta = absolute temperature (K)
|
||||||
|
|
||||||
|
const float ea = hr * es * 1000; // vapor pressure of the air (Pa)
|
||||||
|
const float mw = 18.01528; // molar mass of water (g⋅mol⁻¹)
|
||||||
|
const float r = 8.31446261815324; // molar gas constant (J⋅K⁻¹)
|
||||||
|
return (ea * mw) / (r * ta);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace absolute_humidity
|
||||||
|
} // namespace esphome
|
||||||
76
esphome/components/absolute_humidity/absolute_humidity.h
Normal file
76
esphome/components/absolute_humidity/absolute_humidity.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace absolute_humidity {
|
||||||
|
|
||||||
|
/// Enum listing all implemented saturation vapor pressure equations.
|
||||||
|
enum SaturationVaporPressureEquation {
|
||||||
|
BUCK,
|
||||||
|
TETENS,
|
||||||
|
WOBUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This class implements calculation of absolute humidity from temperature and relative humidity.
|
||||||
|
class AbsoluteHumidityComponent : public sensor::Sensor, public Component {
|
||||||
|
public:
|
||||||
|
AbsoluteHumidityComponent() = default;
|
||||||
|
|
||||||
|
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
|
||||||
|
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
|
||||||
|
void set_equation(SaturationVaporPressureEquation equation) { this->equation_ = equation; }
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void temperature_callback_(float state) {
|
||||||
|
this->next_update_ = true;
|
||||||
|
this->temperature_ = state;
|
||||||
|
}
|
||||||
|
void humidity_callback_(float state) {
|
||||||
|
this->next_update_ = true;
|
||||||
|
this->humidity_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Buck equation for saturation vapor pressure in kPa.
|
||||||
|
*
|
||||||
|
* @param temperature_c Air temperature in °C.
|
||||||
|
*/
|
||||||
|
static float es_buck(float temperature_c);
|
||||||
|
/** Tetens equation for saturation vapor pressure in kPa.
|
||||||
|
*
|
||||||
|
* @param temperature_c Air temperature in °C.
|
||||||
|
*/
|
||||||
|
static float es_tetens(float temperature_c);
|
||||||
|
/** Wobus equation for saturation vapor pressure in kPa.
|
||||||
|
*
|
||||||
|
* @param temperature_c Air temperature in °C.
|
||||||
|
*/
|
||||||
|
static float es_wobus(float temperature_c);
|
||||||
|
|
||||||
|
/** Calculate vapor density (absolute humidity) in g/m³.
|
||||||
|
*
|
||||||
|
* @param es Saturation vapor pressure in kPa.
|
||||||
|
* @param hr Relative humidity 0 to 1.
|
||||||
|
* @param ta Absolute temperature in K.
|
||||||
|
* @param heater_duration The duration in ms that the heater should turn on for when measuring.
|
||||||
|
*/
|
||||||
|
static float vapor_density(float es, float hr, float ta);
|
||||||
|
|
||||||
|
sensor::Sensor *temperature_sensor_{nullptr};
|
||||||
|
sensor::Sensor *humidity_sensor_{nullptr};
|
||||||
|
|
||||||
|
bool next_update_{false};
|
||||||
|
|
||||||
|
float temperature_{NAN};
|
||||||
|
float humidity_{NAN};
|
||||||
|
SaturationVaporPressureEquation equation_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace absolute_humidity
|
||||||
|
} // namespace esphome
|
||||||
56
esphome/components/absolute_humidity/sensor.py
Normal file
56
esphome/components/absolute_humidity/sensor.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_HUMIDITY,
|
||||||
|
CONF_TEMPERATURE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
CONF_EQUATION,
|
||||||
|
ICON_WATER,
|
||||||
|
UNIT_GRAMS_PER_CUBIC_METER,
|
||||||
|
)
|
||||||
|
|
||||||
|
absolute_humidity_ns = cg.esphome_ns.namespace("absolute_humidity")
|
||||||
|
AbsoluteHumidityComponent = absolute_humidity_ns.class_(
|
||||||
|
"AbsoluteHumidityComponent", sensor.Sensor, cg.Component
|
||||||
|
)
|
||||||
|
|
||||||
|
SaturationVaporPressureEquation = absolute_humidity_ns.enum(
|
||||||
|
"SaturationVaporPressureEquation"
|
||||||
|
)
|
||||||
|
EQUATION = {
|
||||||
|
"BUCK": SaturationVaporPressureEquation.BUCK,
|
||||||
|
"TETENS": SaturationVaporPressureEquation.TETENS,
|
||||||
|
"WOBUS": SaturationVaporPressureEquation.WOBUS,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_GRAMS_PER_CUBIC_METER,
|
||||||
|
icon=ICON_WATER,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(AbsoluteHumidityComponent),
|
||||||
|
cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
|
||||||
|
cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor),
|
||||||
|
cv.Optional(CONF_EQUATION, default="WOBUS"): cv.enum(EQUATION, upper=True),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await sensor.new_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
temperature_sensor = await cg.get_variable(config[CONF_TEMPERATURE])
|
||||||
|
cg.add(var.set_temperature_sensor(temperature_sensor))
|
||||||
|
|
||||||
|
humidity_sensor = await cg.get_variable(config[CONF_HUMIDITY])
|
||||||
|
cg.add(var.set_humidity_sensor(humidity_sensor))
|
||||||
|
|
||||||
|
cg.add(var.set_equation(config[CONF_EQUATION]))
|
||||||
@@ -121,11 +121,8 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
|
|||||||
// calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
|
// calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
|
||||||
// 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;
|
||||||
// calculate required value to provide a true RMS voltage output
|
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, (uint32_t)((65535 - (acos(1 - (2 * this->value / 65535.0)) / 3.14159 * 65535)) *
|
|
||||||
(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%
|
||||||
@@ -206,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,6 +11,10 @@ ADC_MODE(ADC_VCC)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RP2040
|
||||||
|
#include <hardware/adc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
@@ -32,9 +36,13 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 b
|
|||||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
#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
|
||||||
|
|
||||||
@@ -63,6 +71,16 @@ void ADCSensor::setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#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() {
|
||||||
@@ -98,6 +116,13 @@ void ADCSensor::dump_config() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +200,29 @@ float ADCSensor::sample() {
|
|||||||
}
|
}
|
||||||
#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
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
38
esphome/components/adc128s102/sensor/__init__.py
Normal file
38
esphome/components/adc128s102/sensor/__init__.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
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(ADC128S102Sensor)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
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 {
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
@@ -63,6 +70,9 @@ CONFIG_SCHEMA = (
|
|||||||
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,11 +102,12 @@ 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,23 +54,25 @@ 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();
|
||||||
|
|
||||||
if (this->invert_position_)
|
if (this->invert_position_)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -15,18 +15,24 @@ AnalogThresholdBinarySensor = analog_threshold_ns.class_(
|
|||||||
CONF_UPPER = "upper"
|
CONF_UPPER = "upper"
|
||||||
CONF_LOWER = "lower"
|
CONF_LOWER = "lower"
|
||||||
|
|
||||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
CONFIG_SCHEMA = (
|
||||||
|
binary_sensor.binary_sensor_schema(AnalogThresholdBinarySensor)
|
||||||
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(AnalogThresholdBinarySensor),
|
|
||||||
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
||||||
cv.Required(CONF_THRESHOLD): cv.Any(
|
cv.Required(CONF_THRESHOLD): cv.Any(
|
||||||
cv.float_,
|
cv.float_,
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{cv.Required(CONF_UPPER): cv.float_, cv.Required(CONF_LOWER): cv.float_}
|
{
|
||||||
|
cv.Required(CONF_UPPER): cv.float_,
|
||||||
|
cv.Required(CONF_LOWER): cv.float_,
|
||||||
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
|
|||||||
@@ -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(
|
||||||
{
|
{
|
||||||
@@ -76,8 +76,6 @@ async def to_code(config):
|
|||||||
pos = 0
|
pos = 0
|
||||||
for frameIndex in range(frames):
|
for frameIndex in range(frames):
|
||||||
image.seek(frameIndex)
|
image.seek(frameIndex)
|
||||||
if CONF_RESIZE in config:
|
|
||||||
image.thumbnail(config[CONF_RESIZE])
|
|
||||||
frame = image.convert("RGB")
|
frame = image.convert("RGB")
|
||||||
if CONF_RESIZE in config:
|
if CONF_RESIZE in config:
|
||||||
frame = frame.resize([width, height])
|
frame = frame.resize([width, height])
|
||||||
@@ -117,7 +115,7 @@ async def to_code(config):
|
|||||||
data[pos] = rgb & 255
|
data[pos] = rgb & 255
|
||||||
pos += 1
|
pos += 1
|
||||||
|
|
||||||
elif config[CONF_TYPE] == "BINARY":
|
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,18 +34,22 @@ 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 =
|
||||||
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
pkt->length, 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(), 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 =
|
||||||
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
pkt->length, 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(), status);
|
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
|
void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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 =
|
||||||
|
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||||
pkt->length, 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(), 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};
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ service APIConnection {
|
|||||||
rpc subscribe_logs (SubscribeLogsRequest) returns (void) {}
|
rpc subscribe_logs (SubscribeLogsRequest) returns (void) {}
|
||||||
rpc subscribe_homeassistant_services (SubscribeHomeassistantServicesRequest) returns (void) {}
|
rpc subscribe_homeassistant_services (SubscribeHomeassistantServicesRequest) returns (void) {}
|
||||||
rpc subscribe_home_assistant_states (SubscribeHomeAssistantStatesRequest) returns (void) {}
|
rpc subscribe_home_assistant_states (SubscribeHomeAssistantStatesRequest) returns (void) {}
|
||||||
rpc subscribe_bluetooth_le_advertisements (SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
|
|
||||||
rpc get_time (GetTimeRequest) returns (GetTimeResponse) {
|
rpc get_time (GetTimeRequest) returns (GetTimeResponse) {
|
||||||
option (needs_authentication) = false;
|
option (needs_authentication) = false;
|
||||||
}
|
}
|
||||||
@@ -44,6 +43,19 @@ service APIConnection {
|
|||||||
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 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) {}
|
||||||
|
rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
|
||||||
|
|
||||||
|
rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,6 +90,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.
|
||||||
@@ -192,7 +206,13 @@ message DeviceInfoResponse {
|
|||||||
|
|
||||||
uint32 webserver_port = 10;
|
uint32 webserver_port = 10;
|
||||||
|
|
||||||
bool has_bluetooth_proxy = 11;
|
uint32 bluetooth_proxy_version = 11;
|
||||||
|
|
||||||
|
string manufacturer = 12;
|
||||||
|
|
||||||
|
string friendly_name = 13;
|
||||||
|
|
||||||
|
uint32 voice_assistant_version = 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListEntitiesRequest {
|
message ListEntitiesRequest {
|
||||||
@@ -772,6 +792,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;
|
||||||
@@ -813,7 +834,7 @@ message ListEntitiesClimateResponse {
|
|||||||
repeated ClimateMode supported_modes = 7;
|
repeated ClimateMode supported_modes = 7;
|
||||||
float visual_min_temperature = 8;
|
float visual_min_temperature = 8;
|
||||||
float visual_max_temperature = 9;
|
float visual_max_temperature = 9;
|
||||||
float visual_temperature_step = 10;
|
float visual_target_temperature_step = 10;
|
||||||
// for older peer versions - in new system this
|
// for older peer versions - in new system this
|
||||||
// is if CLIMATE_PRESET_AWAY exists is supported_presets
|
// is if CLIMATE_PRESET_AWAY exists is supported_presets
|
||||||
bool legacy_supports_away = 11;
|
bool legacy_supports_away = 11;
|
||||||
@@ -826,6 +847,7 @@ message ListEntitiesClimateResponse {
|
|||||||
bool disabled_by_default = 18;
|
bool disabled_by_default = 18;
|
||||||
string icon = 19;
|
string icon = 19;
|
||||||
EntityCategory entity_category = 20;
|
EntityCategory entity_category = 20;
|
||||||
|
float visual_current_temperature_step = 21;
|
||||||
}
|
}
|
||||||
message ClimateStateResponse {
|
message ClimateStateResponse {
|
||||||
option (id) = 47;
|
option (id) = 47;
|
||||||
@@ -902,6 +924,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;
|
||||||
@@ -1107,11 +1130,13 @@ message MediaPlayerCommandRequest {
|
|||||||
message SubscribeBluetoothLEAdvertisementsRequest {
|
message SubscribeBluetoothLEAdvertisementsRequest {
|
||||||
option (id) = 66;
|
option (id) = 66;
|
||||||
option (source) = SOURCE_CLIENT;
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
}
|
}
|
||||||
|
|
||||||
message BluetoothServiceData {
|
message BluetoothServiceData {
|
||||||
string uuid = 1;
|
string uuid = 1;
|
||||||
repeated uint32 data = 2 [packed=false];
|
repeated uint32 legacy_data = 2 [deprecated = true];
|
||||||
|
bytes data = 3; // Changed in proto version 1.7
|
||||||
}
|
}
|
||||||
message BluetoothLEAdvertisementResponse {
|
message BluetoothLEAdvertisementResponse {
|
||||||
option (id) = 67;
|
option (id) = 67;
|
||||||
@@ -1126,4 +1151,286 @@ message BluetoothLEAdvertisementResponse {
|
|||||||
repeated string service_uuids = 4;
|
repeated string service_uuids = 4;
|
||||||
repeated BluetoothServiceData service_data = 5;
|
repeated BluetoothServiceData service_data = 5;
|
||||||
repeated BluetoothServiceData manufacturer_data = 6;
|
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;
|
||||||
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothDevicePairingResponse {
|
||||||
|
option (id) = 85;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
bool paired = 2;
|
||||||
|
int32 error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothDeviceUnpairingResponse {
|
||||||
|
option (id) = 86;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
bool success = 2;
|
||||||
|
int32 error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UnsubscribeBluetoothLEAdvertisementsRequest {
|
||||||
|
option (id) = 87;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
}
|
||||||
|
|
||||||
|
message BluetoothDeviceClearCacheResponse {
|
||||||
|
option (id) = 88;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||||
|
|
||||||
|
uint64 address = 1;
|
||||||
|
bool success = 2;
|
||||||
|
int32 error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PUSH TO TALK ====================
|
||||||
|
message SubscribeVoiceAssistantRequest {
|
||||||
|
option (id) = 89;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_VOICE_ASSISTANT";
|
||||||
|
|
||||||
|
bool subscribe = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message VoiceAssistantRequest {
|
||||||
|
option (id) = 90;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_VOICE_ASSISTANT";
|
||||||
|
|
||||||
|
bool start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message VoiceAssistantResponse {
|
||||||
|
option (id) = 91;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_VOICE_ASSISTANT";
|
||||||
|
|
||||||
|
uint32 port = 1;
|
||||||
|
bool error = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VoiceAssistantEvent {
|
||||||
|
VOICE_ASSISTANT_ERROR = 0;
|
||||||
|
VOICE_ASSISTANT_RUN_START = 1;
|
||||||
|
VOICE_ASSISTANT_RUN_END = 2;
|
||||||
|
VOICE_ASSISTANT_STT_START = 3;
|
||||||
|
VOICE_ASSISTANT_STT_END = 4;
|
||||||
|
VOICE_ASSISTANT_INTENT_START = 5;
|
||||||
|
VOICE_ASSISTANT_INTENT_END = 6;
|
||||||
|
VOICE_ASSISTANT_TTS_START = 7;
|
||||||
|
VOICE_ASSISTANT_TTS_END = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message VoiceAssistantEventData {
|
||||||
|
string name = 1;
|
||||||
|
string value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message VoiceAssistantEventResponse {
|
||||||
|
option (id) = 92;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_VOICE_ASSISTANT";
|
||||||
|
|
||||||
|
VoiceAssistantEvent event_type = 1;
|
||||||
|
repeated VoiceAssistantEventData data = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#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 <cinttypes>
|
||||||
|
#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,6 +13,12 @@
|
|||||||
#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_BLUETOOTH_PROXY
|
||||||
|
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
#include "esphome/components/voice_assistant/voice_assistant.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
@@ -177,6 +184,7 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_
|
|||||||
ListEntitiesBinarySensorResponse msg;
|
ListEntitiesBinarySensorResponse msg;
|
||||||
msg.object_id = binary_sensor->get_object_id();
|
msg.object_id = binary_sensor->get_object_id();
|
||||||
msg.key = binary_sensor->get_object_id_hash();
|
msg.key = binary_sensor->get_object_id_hash();
|
||||||
|
if (binary_sensor->has_own_name())
|
||||||
msg.name = binary_sensor->get_name();
|
msg.name = binary_sensor->get_name();
|
||||||
msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
|
msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
|
||||||
msg.device_class = binary_sensor->get_device_class();
|
msg.device_class = binary_sensor->get_device_class();
|
||||||
@@ -209,6 +217,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
|
|||||||
ListEntitiesCoverResponse msg;
|
ListEntitiesCoverResponse msg;
|
||||||
msg.key = cover->get_object_id_hash();
|
msg.key = cover->get_object_id_hash();
|
||||||
msg.object_id = cover->get_object_id();
|
msg.object_id = cover->get_object_id();
|
||||||
|
if (cover->has_own_name())
|
||||||
msg.name = cover->get_name();
|
msg.name = cover->get_name();
|
||||||
msg.unique_id = get_default_unique_id("cover", cover);
|
msg.unique_id = get_default_unique_id("cover", cover);
|
||||||
msg.assumed_state = traits.get_is_assumed_state();
|
msg.assumed_state = traits.get_is_assumed_state();
|
||||||
@@ -272,6 +281,7 @@ bool APIConnection::send_fan_info(fan::Fan *fan) {
|
|||||||
ListEntitiesFanResponse msg;
|
ListEntitiesFanResponse msg;
|
||||||
msg.key = fan->get_object_id_hash();
|
msg.key = fan->get_object_id_hash();
|
||||||
msg.object_id = fan->get_object_id();
|
msg.object_id = fan->get_object_id();
|
||||||
|
if (fan->has_own_name())
|
||||||
msg.name = fan->get_name();
|
msg.name = fan->get_name();
|
||||||
msg.unique_id = get_default_unique_id("fan", fan);
|
msg.unique_id = get_default_unique_id("fan", fan);
|
||||||
msg.supports_oscillation = traits.supports_oscillation();
|
msg.supports_oscillation = traits.supports_oscillation();
|
||||||
@@ -334,6 +344,7 @@ bool APIConnection::send_light_info(light::LightState *light) {
|
|||||||
ListEntitiesLightResponse msg;
|
ListEntitiesLightResponse msg;
|
||||||
msg.key = light->get_object_id_hash();
|
msg.key = light->get_object_id_hash();
|
||||||
msg.object_id = light->get_object_id();
|
msg.object_id = light->get_object_id();
|
||||||
|
if (light->has_own_name())
|
||||||
msg.name = light->get_name();
|
msg.name = light->get_name();
|
||||||
msg.unique_id = get_default_unique_id("light", light);
|
msg.unique_id = get_default_unique_id("light", light);
|
||||||
|
|
||||||
@@ -415,6 +426,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
|
|||||||
ListEntitiesSensorResponse msg;
|
ListEntitiesSensorResponse msg;
|
||||||
msg.key = sensor->get_object_id_hash();
|
msg.key = sensor->get_object_id_hash();
|
||||||
msg.object_id = sensor->get_object_id();
|
msg.object_id = sensor->get_object_id();
|
||||||
|
if (sensor->has_own_name())
|
||||||
msg.name = sensor->get_name();
|
msg.name = sensor->get_name();
|
||||||
msg.unique_id = sensor->unique_id();
|
msg.unique_id = sensor->unique_id();
|
||||||
if (msg.unique_id.empty())
|
if (msg.unique_id.empty())
|
||||||
@@ -445,6 +457,7 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
|
|||||||
ListEntitiesSwitchResponse msg;
|
ListEntitiesSwitchResponse msg;
|
||||||
msg.key = a_switch->get_object_id_hash();
|
msg.key = a_switch->get_object_id_hash();
|
||||||
msg.object_id = a_switch->get_object_id();
|
msg.object_id = a_switch->get_object_id();
|
||||||
|
if (a_switch->has_own_name())
|
||||||
msg.name = a_switch->get_name();
|
msg.name = a_switch->get_name();
|
||||||
msg.unique_id = get_default_unique_id("switch", a_switch);
|
msg.unique_id = get_default_unique_id("switch", a_switch);
|
||||||
msg.icon = a_switch->get_icon();
|
msg.icon = a_switch->get_icon();
|
||||||
@@ -530,6 +543,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
|||||||
ListEntitiesClimateResponse msg;
|
ListEntitiesClimateResponse msg;
|
||||||
msg.key = climate->get_object_id_hash();
|
msg.key = climate->get_object_id_hash();
|
||||||
msg.object_id = climate->get_object_id();
|
msg.object_id = climate->get_object_id();
|
||||||
|
if (climate->has_own_name())
|
||||||
msg.name = climate->get_name();
|
msg.name = climate->get_name();
|
||||||
msg.unique_id = get_default_unique_id("climate", climate);
|
msg.unique_id = get_default_unique_id("climate", climate);
|
||||||
|
|
||||||
@@ -545,7 +559,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
|||||||
|
|
||||||
msg.visual_min_temperature = traits.get_visual_min_temperature();
|
msg.visual_min_temperature = traits.get_visual_min_temperature();
|
||||||
msg.visual_max_temperature = traits.get_visual_max_temperature();
|
msg.visual_max_temperature = traits.get_visual_max_temperature();
|
||||||
msg.visual_temperature_step = traits.get_visual_temperature_step();
|
msg.visual_target_temperature_step = traits.get_visual_target_temperature_step();
|
||||||
|
msg.visual_current_temperature_step = traits.get_visual_current_temperature_step();
|
||||||
|
|
||||||
msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
|
msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
|
||||||
msg.supports_action = traits.get_supports_action();
|
msg.supports_action = traits.get_supports_action();
|
||||||
|
|
||||||
@@ -606,6 +622,7 @@ bool APIConnection::send_number_info(number::Number *number) {
|
|||||||
ListEntitiesNumberResponse msg;
|
ListEntitiesNumberResponse msg;
|
||||||
msg.key = number->get_object_id_hash();
|
msg.key = number->get_object_id_hash();
|
||||||
msg.object_id = number->get_object_id();
|
msg.object_id = number->get_object_id();
|
||||||
|
if (number->has_own_name())
|
||||||
msg.name = number->get_name();
|
msg.name = number->get_name();
|
||||||
msg.unique_id = get_default_unique_id("number", number);
|
msg.unique_id = get_default_unique_id("number", number);
|
||||||
msg.icon = number->get_icon();
|
msg.icon = number->get_icon();
|
||||||
@@ -613,6 +630,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();
|
||||||
@@ -646,6 +664,7 @@ bool APIConnection::send_select_info(select::Select *select) {
|
|||||||
ListEntitiesSelectResponse msg;
|
ListEntitiesSelectResponse msg;
|
||||||
msg.key = select->get_object_id_hash();
|
msg.key = select->get_object_id_hash();
|
||||||
msg.object_id = select->get_object_id();
|
msg.object_id = select->get_object_id();
|
||||||
|
if (select->has_own_name())
|
||||||
msg.name = select->get_name();
|
msg.name = select->get_name();
|
||||||
msg.unique_id = get_default_unique_id("select", select);
|
msg.unique_id = get_default_unique_id("select", select);
|
||||||
msg.icon = select->get_icon();
|
msg.icon = select->get_icon();
|
||||||
@@ -673,6 +692,7 @@ bool APIConnection::send_button_info(button::Button *button) {
|
|||||||
ListEntitiesButtonResponse msg;
|
ListEntitiesButtonResponse msg;
|
||||||
msg.key = button->get_object_id_hash();
|
msg.key = button->get_object_id_hash();
|
||||||
msg.object_id = button->get_object_id();
|
msg.object_id = button->get_object_id();
|
||||||
|
if (button->has_own_name())
|
||||||
msg.name = button->get_name();
|
msg.name = button->get_name();
|
||||||
msg.unique_id = get_default_unique_id("button", button);
|
msg.unique_id = get_default_unique_id("button", button);
|
||||||
msg.icon = button->get_icon();
|
msg.icon = button->get_icon();
|
||||||
@@ -704,6 +724,7 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) {
|
|||||||
ListEntitiesLockResponse msg;
|
ListEntitiesLockResponse msg;
|
||||||
msg.key = a_lock->get_object_id_hash();
|
msg.key = a_lock->get_object_id_hash();
|
||||||
msg.object_id = a_lock->get_object_id();
|
msg.object_id = a_lock->get_object_id();
|
||||||
|
if (a_lock->has_own_name())
|
||||||
msg.name = a_lock->get_name();
|
msg.name = a_lock->get_name();
|
||||||
msg.unique_id = get_default_unique_id("lock", a_lock);
|
msg.unique_id = get_default_unique_id("lock", a_lock);
|
||||||
msg.icon = a_lock->get_icon();
|
msg.icon = a_lock->get_icon();
|
||||||
@@ -749,6 +770,7 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
|
|||||||
ListEntitiesMediaPlayerResponse msg;
|
ListEntitiesMediaPlayerResponse msg;
|
||||||
msg.key = media_player->get_object_id_hash();
|
msg.key = media_player->get_object_id_hash();
|
||||||
msg.object_id = media_player->get_object_id();
|
msg.object_id = media_player->get_object_id();
|
||||||
|
if (media_player->has_own_name())
|
||||||
msg.name = media_player->get_name();
|
msg.name = media_player->get_name();
|
||||||
msg.unique_id = get_default_unique_id("media_player", media_player);
|
msg.unique_id = get_default_unique_id("media_player", media_player);
|
||||||
msg.icon = media_player->get_icon();
|
msg.icon = media_player->get_icon();
|
||||||
@@ -793,6 +815,7 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
|
|||||||
ListEntitiesCameraResponse msg;
|
ListEntitiesCameraResponse msg;
|
||||||
msg.key = camera->get_object_id_hash();
|
msg.key = camera->get_object_id_hash();
|
||||||
msg.object_id = camera->get_object_id();
|
msg.object_id = camera->get_object_id();
|
||||||
|
if (camera->has_own_name())
|
||||||
msg.name = camera->get_name();
|
msg.name = camera->get_name();
|
||||||
msg.unique_id = get_default_unique_id("camera", camera);
|
msg.unique_id = get_default_unique_id("camera", camera);
|
||||||
msg.disabled_by_default = camera->is_disabled_by_default();
|
msg.disabled_by_default = camera->is_disabled_by_default();
|
||||||
@@ -823,6 +846,80 @@ 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
|
||||||
|
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
bool APIConnection::request_voice_assistant(bool start) {
|
||||||
|
if (!this->voice_assistant_subscription_)
|
||||||
|
return false;
|
||||||
|
VoiceAssistantRequest msg;
|
||||||
|
msg.start = start;
|
||||||
|
return this->send_voice_assistant_request(msg);
|
||||||
|
}
|
||||||
|
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
|
||||||
|
if (voice_assistant::global_voice_assistant != nullptr) {
|
||||||
|
struct sockaddr_storage storage;
|
||||||
|
socklen_t len = sizeof(storage);
|
||||||
|
this->helper_->getpeername((struct sockaddr *) &storage, &len);
|
||||||
|
voice_assistant::global_voice_assistant->start(&storage, msg.port);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
|
||||||
|
if (voice_assistant::global_voice_assistant != nullptr) {
|
||||||
|
voice_assistant::global_voice_assistant->on_event(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
@@ -840,11 +937,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 %" PRIu32 ".%" PRIu32, 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();
|
||||||
|
|
||||||
@@ -873,9 +973,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;
|
||||||
@@ -888,7 +994,12 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
|||||||
resp.webserver_port = USE_WEBSERVER_PORT;
|
resp.webserver_port = USE_WEBSERVER_PORT;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_BLUETOOTH_PROXY
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
resp.has_bluetooth_proxy = true;
|
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active()
|
||||||
|
? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION
|
||||||
|
: bluetooth_proxy::PASSIVE_ONLY_VERSION;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
resp.voice_assistant_version = 1;
|
||||||
#endif
|
#endif
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
#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 "esphome/core/defines.h"
|
||||||
|
|
||||||
#ifdef USE_BLUETOOTH_PROXY
|
#include <vector>
|
||||||
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
@@ -99,11 +98,24 @@ class APIConnection : public APIServerConnection {
|
|||||||
this->send_homeassistant_service_response(call);
|
this->send_homeassistant_service_response(call);
|
||||||
}
|
}
|
||||||
#ifdef USE_BLUETOOTH_PROXY
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call) {
|
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
|
||||||
if (!this->bluetooth_le_advertisement_subscription_)
|
this->bluetooth_le_advertisement_subscription_ = true;
|
||||||
return false;
|
|
||||||
return this->send_bluetooth_le_advertisement_response(call);
|
|
||||||
}
|
}
|
||||||
|
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override {
|
||||||
|
this->bluetooth_le_advertisement_subscription_ = false;
|
||||||
|
}
|
||||||
|
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
|
#endif
|
||||||
#ifdef USE_HOMEASSISTANT_TIME
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
void send_time_request() {
|
void send_time_request() {
|
||||||
@@ -112,6 +124,15 @@ class APIConnection : public APIServerConnection {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
|
||||||
|
this->voice_assistant_subscription_ = msg.subscribe;
|
||||||
|
}
|
||||||
|
bool request_voice_assistant(bool start);
|
||||||
|
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
|
||||||
|
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
void on_disconnect_response(const DisconnectResponse &value) override;
|
void on_disconnect_response(const DisconnectResponse &value) override;
|
||||||
void on_ping_response(const PingResponse &value) override {
|
void on_ping_response(const PingResponse &value) override {
|
||||||
// we initiated ping
|
// we initiated ping
|
||||||
@@ -145,9 +166,7 @@ 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();
|
||||||
@@ -181,6 +200,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
|
||||||
@@ -190,7 +211,12 @@ 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_{true};
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
|
bool bluetooth_le_advertisement_subscription_{false};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
bool voice_assistant_subscription_{false};
|
||||||
|
#endif
|
||||||
bool next_close_ = false;
|
bool next_close_ = false;
|
||||||
APIServer *parent_;
|
APIServer *parent_;
|
||||||
InitialStateIterator initial_state_iterator_;
|
InitialStateIterator initial_state_iterator_;
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ APIError APINoiseFrameHelper::state_action_() {
|
|||||||
if (aerr != APIError::OK)
|
if (aerr != APIError::OK)
|
||||||
return aerr;
|
return aerr;
|
||||||
// ignore contents, may be used in future for flags
|
// ignore contents, may be used in future for flags
|
||||||
prologue_.push_back((uint8_t)(frame.msg.size() >> 8));
|
prologue_.push_back((uint8_t) (frame.msg.size() >> 8));
|
||||||
prologue_.push_back((uint8_t) frame.msg.size());
|
prologue_.push_back((uint8_t) frame.msg.size());
|
||||||
prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end());
|
prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end());
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
|
|||||||
// tmpbuf[1], tmpbuf[2] to be set later
|
// tmpbuf[1], tmpbuf[2] to be set later
|
||||||
const uint8_t msg_offset = 3;
|
const uint8_t msg_offset = 3;
|
||||||
const uint8_t payload_offset = msg_offset + 4;
|
const uint8_t payload_offset = msg_offset + 4;
|
||||||
tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8); // type
|
tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8); // type
|
||||||
tmpbuf[msg_offset + 1] = (uint8_t) type;
|
tmpbuf[msg_offset + 1] = (uint8_t) type;
|
||||||
tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8); // data_len
|
tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len
|
||||||
tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
|
tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
|
||||||
// copy data
|
// copy data
|
||||||
std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
|
std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
|
||||||
@@ -512,7 +512,7 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t total_len = 3 + mbuf.size;
|
size_t total_len = 3 + mbuf.size;
|
||||||
tmpbuf[1] = (uint8_t)(mbuf.size >> 8);
|
tmpbuf[1] = (uint8_t) (mbuf.size >> 8);
|
||||||
tmpbuf[2] = (uint8_t) mbuf.size;
|
tmpbuf[2] = (uint8_t) mbuf.size;
|
||||||
|
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
@@ -610,12 +610,15 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
|
|||||||
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
|
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
|
||||||
uint8_t header[3];
|
uint8_t header[3];
|
||||||
header[0] = 0x01; // indicator
|
header[0] = 0x01; // indicator
|
||||||
header[1] = (uint8_t)(len >> 8);
|
header[1] = (uint8_t) (len >> 8);
|
||||||
header[2] = (uint8_t) len;
|
header[2] = (uint8_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;
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
#include "noise/protocol.h"
|
#include "noise/protocol.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "esphome/components/socket/socket.h"
|
|
||||||
#include "api_noise_context.h"
|
#include "api_noise_context.h"
|
||||||
|
#include "esphome/components/socket/socket.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
@@ -67,6 +67,7 @@ class APIFrameHelper {
|
|||||||
virtual bool can_write_without_blocking() = 0;
|
virtual bool can_write_without_blocking() = 0;
|
||||||
virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0;
|
virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0;
|
||||||
virtual std::string getpeername() = 0;
|
virtual std::string getpeername() = 0;
|
||||||
|
virtual int getpeername(struct sockaddr *addr, socklen_t *addrlen) = 0;
|
||||||
virtual APIError close() = 0;
|
virtual APIError close() = 0;
|
||||||
virtual APIError shutdown(int how) = 0;
|
virtual APIError shutdown(int how) = 0;
|
||||||
// Give this helper a name for logging
|
// Give this helper a name for logging
|
||||||
@@ -84,7 +85,10 @@ class APINoiseFrameHelper : public APIFrameHelper {
|
|||||||
APIError read_packet(ReadPacketBuffer *buffer) override;
|
APIError read_packet(ReadPacketBuffer *buffer) override;
|
||||||
bool can_write_without_blocking() override;
|
bool can_write_without_blocking() override;
|
||||||
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
|
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
|
||||||
std::string getpeername() override { return socket_->getpeername(); }
|
std::string getpeername() override { return this->socket_->getpeername(); }
|
||||||
|
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
|
||||||
|
return this->socket_->getpeername(addr, addrlen);
|
||||||
|
}
|
||||||
APIError close() override;
|
APIError close() override;
|
||||||
APIError shutdown(int how) override;
|
APIError shutdown(int how) override;
|
||||||
// Give this helper a name for logging
|
// Give this helper a name for logging
|
||||||
@@ -116,9 +120,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 {
|
||||||
@@ -144,7 +148,10 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
|
|||||||
APIError read_packet(ReadPacketBuffer *buffer) override;
|
APIError read_packet(ReadPacketBuffer *buffer) override;
|
||||||
bool can_write_without_blocking() override;
|
bool can_write_without_blocking() override;
|
||||||
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
|
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
|
||||||
std::string getpeername() override { return socket_->getpeername(); }
|
std::string getpeername() override { return this->socket_->getpeername(); }
|
||||||
|
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
|
||||||
|
return this->socket_->getpeername(addr, addrlen);
|
||||||
|
}
|
||||||
APIError close() override;
|
APIError close() override;
|
||||||
APIError shutdown(int how) override;
|
APIError shutdown(int how) override;
|
||||||
// Give this helper a name for logging
|
// Give this helper a name for logging
|
||||||
|
|||||||
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