forked from home-assistant/core
Compare commits
765 Commits
2023.10.3
...
revert-102
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae71cc5fc5 | ||
|
|
30ba78cf82 | ||
|
|
1176003b51 | ||
|
|
a2bc2bf8a0 | ||
|
|
54ba376b4b | ||
|
|
268425b5e3 | ||
|
|
4ee9a6f130 | ||
|
|
b980ed3eac | ||
|
|
a97e34f28e | ||
|
|
04b883a8e9 | ||
|
|
164872e1af | ||
|
|
bc45de627a | ||
|
|
c8007b841b | ||
|
|
721c45b7a3 | ||
|
|
37fdb4950a | ||
|
|
c2abc3dcec | ||
|
|
5e30c2ab9c | ||
|
|
7d2fa5bf60 | ||
|
|
e936ca0cb1 | ||
|
|
0adb6fb02c | ||
|
|
27f6c6fdf4 | ||
|
|
2dfb3ba693 | ||
|
|
e3b238861d | ||
|
|
3f88c518a5 | ||
|
|
4bf0d6e536 | ||
|
|
6b618fc95a | ||
|
|
b416c8fbf6 | ||
|
|
a77a0ef4a5 | ||
|
|
877410bb9d | ||
|
|
1fd7378caf | ||
|
|
c9c152d46d | ||
|
|
f8ed051f01 | ||
|
|
0b5218ec96 | ||
|
|
409afddeb5 | ||
|
|
82c0610050 | ||
|
|
af0b53cc79 | ||
|
|
a04c37c59f | ||
|
|
b79eae2e94 | ||
|
|
e4943dd1e6 | ||
|
|
392b53e256 | ||
|
|
1a8558012f | ||
|
|
ee8037afc1 | ||
|
|
58e84b7ba1 | ||
|
|
1412c2ea6e | ||
|
|
3259e39170 | ||
|
|
06a2664a07 | ||
|
|
51f989c57a | ||
|
|
8bfd418c3e | ||
|
|
af264c6e0d | ||
|
|
1621310ba7 | ||
|
|
1973287c91 | ||
|
|
b3bd34a024 | ||
|
|
311e539c0e | ||
|
|
d5862c350a | ||
|
|
9820f4288f | ||
|
|
00607fb778 | ||
|
|
62d8472757 | ||
|
|
973b8900a9 | ||
|
|
215febc912 | ||
|
|
c4f562ff6a | ||
|
|
1801a7738c | ||
|
|
6f2245bba3 | ||
|
|
0ebc97ad85 | ||
|
|
242124504b | ||
|
|
f4d91043fc | ||
|
|
aa9301be32 | ||
|
|
51596c6231 | ||
|
|
f9dbddc884 | ||
|
|
89f9d64bf5 | ||
|
|
f626f3bc1e | ||
|
|
017c699e19 | ||
|
|
235a3486ee | ||
|
|
f0f3a43b09 | ||
|
|
e8146e5565 | ||
|
|
c36166f01d | ||
|
|
864b69e586 | ||
|
|
bd0df2f18f | ||
|
|
e5b5858915 | ||
|
|
3896ed47be | ||
|
|
faa149b71a | ||
|
|
9f3a733f73 | ||
|
|
a8f0a66c27 | ||
|
|
aa5c4d8786 | ||
|
|
09a8b8567d | ||
|
|
5cec687247 | ||
|
|
29f61349ea | ||
|
|
5aefe963ae | ||
|
|
013e580c02 | ||
|
|
41b59b6990 | ||
|
|
a2c60d9015 | ||
|
|
55a8f01dcf | ||
|
|
7e6c14d062 | ||
|
|
3c455391c2 | ||
|
|
b881057aa6 | ||
|
|
f51743f123 | ||
|
|
b70262fe8c | ||
|
|
f08a3b96e4 | ||
|
|
f6238c16f6 | ||
|
|
6f84549784 | ||
|
|
038040ffbe | ||
|
|
e1972ba3c8 | ||
|
|
1bd0b2d05f | ||
|
|
5ff6779f5c | ||
|
|
dd4ac823d3 | ||
|
|
27b5a9e074 | ||
|
|
6be401918e | ||
|
|
2d6dc2bccc | ||
|
|
31daac61a9 | ||
|
|
1939beeca6 | ||
|
|
14483db892 | ||
|
|
0bd416e53d | ||
|
|
c7affa75d4 | ||
|
|
73ac2d3dcc | ||
|
|
00978026cd | ||
|
|
c9cba77940 | ||
|
|
467d24548d | ||
|
|
ab67304ebc | ||
|
|
d55b6a0839 | ||
|
|
dd15e3f706 | ||
|
|
7963008a1e | ||
|
|
3599ddfd9f | ||
|
|
f5e681ad33 | ||
|
|
221efd7d4d | ||
|
|
f896b82b49 | ||
|
|
ec6128d9c4 | ||
|
|
a187f05da0 | ||
|
|
f12ce41d00 | ||
|
|
3aba98a297 | ||
|
|
1a45b0af28 | ||
|
|
c916ac67bd | ||
|
|
f7e84fcb60 | ||
|
|
2d7f054058 | ||
|
|
3fb79829ef | ||
|
|
b2bbe4f4b8 | ||
|
|
edce212dc9 | ||
|
|
1e1dbf3cef | ||
|
|
24a1e540b9 | ||
|
|
1371a03d14 | ||
|
|
1b83620213 | ||
|
|
08d5d5336a | ||
|
|
406e58df69 | ||
|
|
e9e677d933 | ||
|
|
3cfcffc6f2 | ||
|
|
50c7587ab8 | ||
|
|
cc0491e85d | ||
|
|
5e483c5573 | ||
|
|
da653c36fd | ||
|
|
a187164bf8 | ||
|
|
485c52568d | ||
|
|
20a58d2314 | ||
|
|
d7e195ba40 | ||
|
|
8202071683 | ||
|
|
c042863486 | ||
|
|
16e3ed47e7 | ||
|
|
6f83374f3e | ||
|
|
fe8fb8928c | ||
|
|
712c061ac0 | ||
|
|
25ab622b51 | ||
|
|
e319b04fde | ||
|
|
7d9014ae41 | ||
|
|
f85b4f734c | ||
|
|
4e63823970 | ||
|
|
554ab94782 | ||
|
|
1efbba2631 | ||
|
|
12c4a10cfc | ||
|
|
f1eb28b7ac | ||
|
|
3014a651c3 | ||
|
|
84d0907fc8 | ||
|
|
8a79870e3a | ||
|
|
92e625636a | ||
|
|
c7b1e4186b | ||
|
|
38a0d31edb | ||
|
|
04fdcbe5fa | ||
|
|
bb90c1f168 | ||
|
|
b911f242dd | ||
|
|
3285c982fe | ||
|
|
dcdd4b470c | ||
|
|
e6d9f89991 | ||
|
|
5264cdf382 | ||
|
|
fd435a5416 | ||
|
|
f4e7c5aed3 | ||
|
|
6baa8082d5 | ||
|
|
ec1b3fe6fb | ||
|
|
54c80491e3 | ||
|
|
e6e2aa0ea0 | ||
|
|
5c422c61e9 | ||
|
|
96b450ad39 | ||
|
|
063d74c35d | ||
|
|
e26a2596af | ||
|
|
b57af4e404 | ||
|
|
22c21fdc18 | ||
|
|
f497bcee3a | ||
|
|
9db9f1b8a9 | ||
|
|
c574cefc30 | ||
|
|
5eb0a33795 | ||
|
|
1456809f6a | ||
|
|
d0341c9754 | ||
|
|
3853214496 | ||
|
|
c408b60e4e | ||
|
|
615b02be59 | ||
|
|
c266583bea | ||
|
|
eab4c24f7f | ||
|
|
3a4341dbeb | ||
|
|
fb984b5218 | ||
|
|
651b725cc0 | ||
|
|
d149bffb07 | ||
|
|
90687e9794 | ||
|
|
dae742fba0 | ||
|
|
2d833fd6ea | ||
|
|
dff18b4a16 | ||
|
|
4498c2e8c4 | ||
|
|
9857c0fa3a | ||
|
|
c377cf1ce0 | ||
|
|
857f2e1d86 | ||
|
|
ea61160fd8 | ||
|
|
327bdce561 | ||
|
|
7ec2496c81 | ||
|
|
d00934a8f8 | ||
|
|
393544b3e7 | ||
|
|
870e38e8ba | ||
|
|
4b39d34f4c | ||
|
|
ae62999457 | ||
|
|
afec5b6730 | ||
|
|
159b623b95 | ||
|
|
20fdd45e60 | ||
|
|
c98c18f25e | ||
|
|
606b76c681 | ||
|
|
2531b0bc09 | ||
|
|
1372126bc0 | ||
|
|
22de378d91 | ||
|
|
b9c7613774 | ||
|
|
61104dd726 | ||
|
|
9d6518265c | ||
|
|
d0bff10502 | ||
|
|
664e490cfa | ||
|
|
1b73219137 | ||
|
|
eee294d384 | ||
|
|
9d775bdbf6 | ||
|
|
3bb23a6d88 | ||
|
|
5f35eecf93 | ||
|
|
799342497b | ||
|
|
a65ad37c8b | ||
|
|
43aaf78f7b | ||
|
|
a06d8c4d3f | ||
|
|
42f830600c | ||
|
|
6c1bcae291 | ||
|
|
3cedfbcc66 | ||
|
|
cfb88766c7 | ||
|
|
c3d1db5db6 | ||
|
|
e2e9c84c88 | ||
|
|
d8e541a284 | ||
|
|
e6895b5738 | ||
|
|
60c1a8d56f | ||
|
|
9dd2f37b11 | ||
|
|
29e8814d1b | ||
|
|
4ae5757bc1 | ||
|
|
44a5a2dc06 | ||
|
|
474f4329bc | ||
|
|
af66bc5e3a | ||
|
|
f7c1dd2f79 | ||
|
|
52063537d7 | ||
|
|
7cd376574e | ||
|
|
928086a9e5 | ||
|
|
fc09d87c3c | ||
|
|
ab29c796da | ||
|
|
10fd26df4b | ||
|
|
433c022687 | ||
|
|
eea9de063b | ||
|
|
16c5a12c87 | ||
|
|
912032e8b9 | ||
|
|
25671a2e42 | ||
|
|
6d457e808f | ||
|
|
f891fb6b41 | ||
|
|
4130980100 | ||
|
|
23b379b7da | ||
|
|
9444e1e2ab | ||
|
|
e151358aa1 | ||
|
|
4913e7e846 | ||
|
|
79811e3cd9 | ||
|
|
b8904fa173 | ||
|
|
eaf6197d43 | ||
|
|
6b05f51413 | ||
|
|
88296c1998 | ||
|
|
17c9d85e0e | ||
|
|
d0ba42283c | ||
|
|
c60cc11505 | ||
|
|
ce7573c3ad | ||
|
|
422252e3a0 | ||
|
|
e5ebdf7ad4 | ||
|
|
d0fb994199 | ||
|
|
8dd8af0718 | ||
|
|
653da6e31f | ||
|
|
36e1c740fd | ||
|
|
11740d1e68 | ||
|
|
93f10cdce8 | ||
|
|
3c3f512583 | ||
|
|
24afbf3ae4 | ||
|
|
b4295e909c | ||
|
|
3577547eb3 | ||
|
|
683046272d | ||
|
|
471d1abe47 | ||
|
|
b95060df99 | ||
|
|
b4e4a98f17 | ||
|
|
6f5a72edf2 | ||
|
|
2c3067b9c2 | ||
|
|
36fcf198b1 | ||
|
|
1a348babd4 | ||
|
|
8c14824bd5 | ||
|
|
d237ab6d67 | ||
|
|
e427fc511b | ||
|
|
264eef8dd8 | ||
|
|
148087a1c9 | ||
|
|
dcb5faa305 | ||
|
|
05ee28cae5 | ||
|
|
23e5bc20c2 | ||
|
|
7fe2bfa990 | ||
|
|
dc19290271 | ||
|
|
0eb4567364 | ||
|
|
5b8da03596 | ||
|
|
f9615999db | ||
|
|
1f1a27d6a5 | ||
|
|
547c38a515 | ||
|
|
7b2aa3a369 | ||
|
|
2d1afc1c7d | ||
|
|
76083a0b4c | ||
|
|
302b444269 | ||
|
|
8a4fe5add1 | ||
|
|
89d86fe983 | ||
|
|
5ed8de8348 | ||
|
|
0e499e07d2 | ||
|
|
f8f39a29de | ||
|
|
8fd5d89d43 | ||
|
|
371d988643 | ||
|
|
76e2afbce9 | ||
|
|
2e3013f2f8 | ||
|
|
ae7bb60677 | ||
|
|
6a6f6fd99d | ||
|
|
a302f1a616 | ||
|
|
ce77566783 | ||
|
|
a0a3d91a28 | ||
|
|
85fa364152 | ||
|
|
7d8ea404b3 | ||
|
|
370e3166ee | ||
|
|
2609394b9f | ||
|
|
02567d9bf6 | ||
|
|
2dfc8b9d7f | ||
|
|
4e9ec82082 | ||
|
|
53e97fee0e | ||
|
|
43753b841f | ||
|
|
5f91bdcfc5 | ||
|
|
fecaf9aa60 | ||
|
|
f330bc0f97 | ||
|
|
d712a29052 | ||
|
|
03210d7f81 | ||
|
|
dc18a7f1fb | ||
|
|
ff5504f55f | ||
|
|
8b134f26a9 | ||
|
|
6d2fbeb556 | ||
|
|
536ad57bf4 | ||
|
|
cc3d1a11bd | ||
|
|
c4ce900567 | ||
|
|
0c901435bd | ||
|
|
85af452c6e | ||
|
|
a92919b8fd | ||
|
|
472ab437e8 | ||
|
|
3843e91af0 | ||
|
|
edf510f9c0 | ||
|
|
a4e0b3140b | ||
|
|
b6d8211c6c | ||
|
|
e5f37050a9 | ||
|
|
8870991802 | ||
|
|
dc29190564 | ||
|
|
5c52a15df7 | ||
|
|
6e1c23906c | ||
|
|
3e4edc8edd | ||
|
|
6450ae8d28 | ||
|
|
5730cb1e85 | ||
|
|
91cf719588 | ||
|
|
b70e2f7749 | ||
|
|
52067dbfe5 | ||
|
|
8e3c665fd3 | ||
|
|
dcb3dc254d | ||
|
|
d676d95901 | ||
|
|
830981ddd6 | ||
|
|
5523e9947d | ||
|
|
2276be275d | ||
|
|
7fd89b2959 | ||
|
|
6ce5f190c1 | ||
|
|
f0317f0d59 | ||
|
|
257686fcfe | ||
|
|
6c4ac71218 | ||
|
|
dfea1c2b7c | ||
|
|
fd72ebd733 | ||
|
|
952a17532f | ||
|
|
1915fee9ba | ||
|
|
7db2fdd68c | ||
|
|
ddfad75eb7 | ||
|
|
c66f0e3305 | ||
|
|
6771d4bda4 | ||
|
|
9107e166b4 | ||
|
|
f61627ea08 | ||
|
|
183397e201 | ||
|
|
87c82fb00f | ||
|
|
0b2b486754 | ||
|
|
f116e83b62 | ||
|
|
1a7601ebbe | ||
|
|
8acb4dc1b6 | ||
|
|
7f7c3233bd | ||
|
|
1c70cbaebd | ||
|
|
7d1105228b | ||
|
|
39fd5897cb | ||
|
|
bd38fd9516 | ||
|
|
ffb752c804 | ||
|
|
9b785ef766 | ||
|
|
ba91aaa28d | ||
|
|
535e2b81ce | ||
|
|
265f6653c3 | ||
|
|
6c65db2036 | ||
|
|
b932c67eb7 | ||
|
|
c76ce76824 | ||
|
|
1a8684e314 | ||
|
|
5290396731 | ||
|
|
71ddb282d2 | ||
|
|
4b9296f4f1 | ||
|
|
7b4b8e7516 | ||
|
|
f166e1cc1a | ||
|
|
f7f9331c57 | ||
|
|
60fa02c042 | ||
|
|
ecdb0bb46a | ||
|
|
31bd500222 | ||
|
|
915f5bf84e | ||
|
|
f78199df9f | ||
|
|
00abf49637 | ||
|
|
6d632bd1ab | ||
|
|
9afdc22818 | ||
|
|
c6a3fa30f0 | ||
|
|
deffa50142 | ||
|
|
1944b2952c | ||
|
|
e5d5440385 | ||
|
|
db3a4dec33 | ||
|
|
35293eb98b | ||
|
|
a21990f248 | ||
|
|
66f43ebdc5 | ||
|
|
84fe356782 | ||
|
|
70a0cd579d | ||
|
|
d46dca8950 | ||
|
|
2e4df6d2f2 | ||
|
|
b9090452de | ||
|
|
6393171fa4 | ||
|
|
8a83e810b8 | ||
|
|
f7292d5b00 | ||
|
|
27b6325c32 | ||
|
|
e6e190e7e2 | ||
|
|
7b78cfc090 | ||
|
|
1f122eb688 | ||
|
|
18908740ca | ||
|
|
de658f5ca0 | ||
|
|
b85a078235 | ||
|
|
548a73b367 | ||
|
|
c247170c90 | ||
|
|
d78ee96e2a | ||
|
|
6d1876394e | ||
|
|
fb215479d4 | ||
|
|
db0c5bbbea | ||
|
|
78535b99df | ||
|
|
c6ed022cce | ||
|
|
1b11062b27 | ||
|
|
ba3fd4dee1 | ||
|
|
6420cdb42b | ||
|
|
c48b724dde | ||
|
|
3c5772c1c6 | ||
|
|
4a437e46aa | ||
|
|
5087f0056c | ||
|
|
7c85d84133 | ||
|
|
0f4aae4128 | ||
|
|
faea3b1634 | ||
|
|
3155e62510 | ||
|
|
8c26f66a57 | ||
|
|
b75a59aad0 | ||
|
|
e406b8d1e3 | ||
|
|
b8b28e3ba0 | ||
|
|
d05ba6cd92 | ||
|
|
7d202f78f5 | ||
|
|
d3a67cd984 | ||
|
|
74464fd94e | ||
|
|
3bbef476ee | ||
|
|
55bf309d2f | ||
|
|
9407c49819 | ||
|
|
f4ac2b7eeb | ||
|
|
4709e60ff6 | ||
|
|
8c2a2e5c37 | ||
|
|
da3e36aa3b | ||
|
|
bd93fbe91d | ||
|
|
031a9224fb | ||
|
|
b60401b2b1 | ||
|
|
1a5ad23a10 | ||
|
|
f3864e6e2f | ||
|
|
35be5957c3 | ||
|
|
3018d4edb9 | ||
|
|
e25cf7cbab | ||
|
|
5ae45e398e | ||
|
|
ba5aa7759d | ||
|
|
0221207b0e | ||
|
|
da9c42d457 | ||
|
|
617ce994b4 | ||
|
|
e68627af7f | ||
|
|
c8eb62cf4e | ||
|
|
43c1769004 | ||
|
|
c70c2f4be4 | ||
|
|
207adaf9cd | ||
|
|
8877cafe0c | ||
|
|
73debba60c | ||
|
|
bb7ddddd4c | ||
|
|
475cb7719b | ||
|
|
9ac5bdc832 | ||
|
|
ed8a372f4e | ||
|
|
4e98d39106 | ||
|
|
5d0c8947a1 | ||
|
|
d654c4bc1e | ||
|
|
b2cad2370b | ||
|
|
6359390a78 | ||
|
|
c8d1a7ff4f | ||
|
|
86cf2e29b2 | ||
|
|
1635cbb8a6 | ||
|
|
8dffff3983 | ||
|
|
5edcd7ef0f | ||
|
|
83c5844c2e | ||
|
|
9982483395 | ||
|
|
96aba1c1a6 | ||
|
|
adc7fc0ee4 | ||
|
|
10dcdbf537 | ||
|
|
d2c842ee0c | ||
|
|
62802dd487 | ||
|
|
835982ebe5 | ||
|
|
d5f07ef45f | ||
|
|
3cd4d26eb9 | ||
|
|
1c590f8d0e | ||
|
|
fd2edf6c0a | ||
|
|
79eaaec1a8 | ||
|
|
f7aad4a9e6 | ||
|
|
425d961489 | ||
|
|
97d17637ea | ||
|
|
ca7355b2f3 | ||
|
|
4553de5cbf | ||
|
|
c0904c905d | ||
|
|
7c8c063149 | ||
|
|
00d0767628 | ||
|
|
20188181f7 | ||
|
|
775751ece5 | ||
|
|
b97ec2cfce | ||
|
|
fa90b0f41e | ||
|
|
d009ff8b01 | ||
|
|
67dfd1a86b | ||
|
|
3478666973 | ||
|
|
60fa63a1f0 | ||
|
|
ed74e64f8d | ||
|
|
579590f7c3 | ||
|
|
244f6d8002 | ||
|
|
48a23798d0 | ||
|
|
920bd04099 | ||
|
|
442005e40f | ||
|
|
dd8bd0db5a | ||
|
|
2bfb1e75d3 | ||
|
|
da770df13f | ||
|
|
da1d5fc862 | ||
|
|
c7d533d427 | ||
|
|
1d31def982 | ||
|
|
8a033ee554 | ||
|
|
6853d54050 | ||
|
|
fe316f2233 | ||
|
|
ce55116eb2 | ||
|
|
b8fa065467 | ||
|
|
a428bbfc2e | ||
|
|
b7914582db | ||
|
|
285ad10624 | ||
|
|
62ea4b36cd | ||
|
|
659d437cac | ||
|
|
716a10e556 | ||
|
|
589fd58137 | ||
|
|
0c40c8465e | ||
|
|
3d9073693c | ||
|
|
dce5099d92 | ||
|
|
cb0a05142d | ||
|
|
0e41542ff3 | ||
|
|
7f912cb669 | ||
|
|
2464232f24 | ||
|
|
5975974a37 | ||
|
|
ef066626c8 | ||
|
|
0c8e1a691d | ||
|
|
ca2e335ab9 | ||
|
|
383c63000e | ||
|
|
c951c03447 | ||
|
|
db71e8033c | ||
|
|
7e39acda37 | ||
|
|
c495d607d8 | ||
|
|
a3fe120457 | ||
|
|
1d7d7c3540 | ||
|
|
2d766d43fc | ||
|
|
5754e8721a | ||
|
|
ab6f617797 | ||
|
|
17779c5f0c | ||
|
|
3aa6771835 | ||
|
|
d3c5b9777b | ||
|
|
cd175f679f | ||
|
|
fb724472fb | ||
|
|
f08d66741d | ||
|
|
d14e5dc56a | ||
|
|
8626a4888c | ||
|
|
efca5ba554 | ||
|
|
adf6d34d95 | ||
|
|
3be3593ffa | ||
|
|
5551a345ea | ||
|
|
09ba34fb3a | ||
|
|
63946175ea | ||
|
|
e6504218bc | ||
|
|
d8f1023210 | ||
|
|
1c60597e41 | ||
|
|
2627abb9ef | ||
|
|
cc7e35e299 | ||
|
|
d723a87ea2 | ||
|
|
ab2de18f8f | ||
|
|
956098ae3a | ||
|
|
bdcc6c0143 | ||
|
|
d518cf13e5 | ||
|
|
135570acab | ||
|
|
7c7f00a46d | ||
|
|
727074a1a6 | ||
|
|
99f227229e | ||
|
|
69e588b15e | ||
|
|
44acc88365 | ||
|
|
49e69aff0c | ||
|
|
ca2f45d466 | ||
|
|
2f0ba154b9 | ||
|
|
d0700db7eb | ||
|
|
9d242bf45f | ||
|
|
f248b693d7 | ||
|
|
e4cb19f20d | ||
|
|
6fa3078cfc | ||
|
|
1a9c98e837 | ||
|
|
35616e100d | ||
|
|
054407722d | ||
|
|
74b3c5c690 | ||
|
|
cab30085c5 | ||
|
|
b5f71f9ec7 | ||
|
|
f72f95549c | ||
|
|
9eaf326c0e | ||
|
|
15f945c47e | ||
|
|
02f82d04fe | ||
|
|
a618e8d1cf | ||
|
|
e18e12a2df | ||
|
|
e23e71279f | ||
|
|
100b6fd06f | ||
|
|
4ee6f6c766 | ||
|
|
0fdf04391b | ||
|
|
85e782055b | ||
|
|
d0dc4d0963 | ||
|
|
41cb8526d1 | ||
|
|
1b43d79717 | ||
|
|
56e7e20904 | ||
|
|
e652d37f29 | ||
|
|
6ce6952a06 | ||
|
|
99a76ef4e6 | ||
|
|
f2cf87b0b7 | ||
|
|
b56d25121f | ||
|
|
b33d5fece6 | ||
|
|
78f827697e | ||
|
|
c1cfce116d | ||
|
|
4e4b8de448 | ||
|
|
4c24ff6847 | ||
|
|
cabfbc245d | ||
|
|
9261ad14e2 | ||
|
|
67f7c703f4 | ||
|
|
377f00730a | ||
|
|
1f76abe6f4 | ||
|
|
1db3d3c158 | ||
|
|
8fd0a1b083 | ||
|
|
65c8da3bf1 | ||
|
|
598a8890e9 | ||
|
|
2d58ab0e1c | ||
|
|
b3b5ca9b95 | ||
|
|
f4bf8fa8f1 | ||
|
|
a3808383d5 | ||
|
|
8b7fae5200 | ||
|
|
31ea00f5c7 | ||
|
|
a4a99ce957 | ||
|
|
87ecdfb84f | ||
|
|
5e6735ab6d | ||
|
|
9306e60530 | ||
|
|
fd1f0b0efe | ||
|
|
9b754a58f4 | ||
|
|
b4555c8a92 | ||
|
|
bd2fee289d | ||
|
|
fe30c019b6 | ||
|
|
25855a3ccb | ||
|
|
42eb849cae | ||
|
|
9444a474ec | ||
|
|
47ecce4873 | ||
|
|
d40a08958d | ||
|
|
e6c9a82b5f | ||
|
|
6e3c704a33 | ||
|
|
542ab2dd76 | ||
|
|
7b9c1c3953 | ||
|
|
a1d632c5d1 | ||
|
|
facdc5e862 | ||
|
|
1546dee36e | ||
|
|
581a045617 | ||
|
|
26ba10f4e4 | ||
|
|
1b05418647 | ||
|
|
a5f8774878 | ||
|
|
257e608c13 | ||
|
|
a19c6fe9ff | ||
|
|
339b95c79f | ||
|
|
edcf0b6333 | ||
|
|
591ffa8b68 | ||
|
|
8d972223d8 | ||
|
|
6c39233e00 | ||
|
|
ce083eade9 | ||
|
|
50827405d0 | ||
|
|
b8a7ad916a | ||
|
|
97e5504ddd | ||
|
|
e924622153 | ||
|
|
809abc1445 | ||
|
|
4f90542394 | ||
|
|
2a6a2fa842 | ||
|
|
fb61e34833 | ||
|
|
845d28255e | ||
|
|
f5d8d41ad5 | ||
|
|
d1347d23de | ||
|
|
063bac1665 | ||
|
|
42b2a462c1 | ||
|
|
136fbaa2a8 | ||
|
|
d73cc1eecd | ||
|
|
dbd0c06518 | ||
|
|
0ded0ef4ee | ||
|
|
77c519220d | ||
|
|
f733c43900 | ||
|
|
0a540e1cdb | ||
|
|
f39b2716b0 | ||
|
|
f255a0e546 | ||
|
|
3b381f10d3 | ||
|
|
dc78d15abc | ||
|
|
d8520088e7 | ||
|
|
f0ca27fd08 | ||
|
|
217a895b5a | ||
|
|
b43262014f | ||
|
|
d1f1bdebde | ||
|
|
4a73ccb7db | ||
|
|
3db7bdc630 | ||
|
|
089f87c45b | ||
|
|
d70cb8caa5 | ||
|
|
e1771ae01e | ||
|
|
d41144ee88 | ||
|
|
f757d4c7da | ||
|
|
4f1906ae3e | ||
|
|
dc1d3f727b | ||
|
|
5fe61ca5e7 | ||
|
|
38984dd939 | ||
|
|
b569cb61e9 | ||
|
|
7d07694496 | ||
|
|
6a52283ce0 | ||
|
|
473d20712c | ||
|
|
b3b235cbb7 | ||
|
|
9fe2c08913 | ||
|
|
97f24b855f | ||
|
|
c0c02bf6bb |
24
.coveragerc
24
.coveragerc
@@ -178,6 +178,8 @@ omit =
|
||||
homeassistant/components/comelit/cover.py
|
||||
homeassistant/components/comelit/coordinator.py
|
||||
homeassistant/components/comelit/light.py
|
||||
homeassistant/components/comelit/sensor.py
|
||||
homeassistant/components/comelit/switch.py
|
||||
homeassistant/components/comfoconnect/fan.py
|
||||
homeassistant/components/concord232/alarm_control_panel.py
|
||||
homeassistant/components/concord232/binary_sensor.py
|
||||
@@ -376,6 +378,7 @@ omit =
|
||||
homeassistant/components/fibaro/binary_sensor.py
|
||||
homeassistant/components/fibaro/climate.py
|
||||
homeassistant/components/fibaro/cover.py
|
||||
homeassistant/components/fibaro/event.py
|
||||
homeassistant/components/fibaro/light.py
|
||||
homeassistant/components/fibaro/lock.py
|
||||
homeassistant/components/fibaro/sensor.py
|
||||
@@ -541,12 +544,6 @@ omit =
|
||||
homeassistant/components/hvv_departures/__init__.py
|
||||
homeassistant/components/hvv_departures/binary_sensor.py
|
||||
homeassistant/components/hvv_departures/sensor.py
|
||||
homeassistant/components/hydrawise/__init__.py
|
||||
homeassistant/components/hydrawise/binary_sensor.py
|
||||
homeassistant/components/hydrawise/const.py
|
||||
homeassistant/components/hydrawise/coordinator.py
|
||||
homeassistant/components/hydrawise/sensor.py
|
||||
homeassistant/components/hydrawise/switch.py
|
||||
homeassistant/components/ialarm/alarm_control_panel.py
|
||||
homeassistant/components/iammeter/sensor.py
|
||||
homeassistant/components/iaqualink/binary_sensor.py
|
||||
@@ -563,7 +560,6 @@ omit =
|
||||
homeassistant/components/ifttt/alarm_control_panel.py
|
||||
homeassistant/components/iglo/light.py
|
||||
homeassistant/components/ihc/*
|
||||
homeassistant/components/imap_email_content/sensor.py
|
||||
homeassistant/components/incomfort/*
|
||||
homeassistant/components/insteon/binary_sensor.py
|
||||
homeassistant/components/insteon/climate.py
|
||||
@@ -750,11 +746,6 @@ omit =
|
||||
homeassistant/components/mikrotik/hub.py
|
||||
homeassistant/components/mill/climate.py
|
||||
homeassistant/components/mill/sensor.py
|
||||
homeassistant/components/minecraft_server/__init__.py
|
||||
homeassistant/components/minecraft_server/binary_sensor.py
|
||||
homeassistant/components/minecraft_server/coordinator.py
|
||||
homeassistant/components/minecraft_server/entity.py
|
||||
homeassistant/components/minecraft_server/sensor.py
|
||||
homeassistant/components/minio/minio_helper.py
|
||||
homeassistant/components/mjpeg/camera.py
|
||||
homeassistant/components/mjpeg/util.py
|
||||
@@ -795,6 +786,7 @@ omit =
|
||||
homeassistant/components/mystrom/binary_sensor.py
|
||||
homeassistant/components/mystrom/light.py
|
||||
homeassistant/components/mystrom/switch.py
|
||||
homeassistant/components/mystrom/sensor.py
|
||||
homeassistant/components/nad/media_player.py
|
||||
homeassistant/components/nanoleaf/__init__.py
|
||||
homeassistant/components/nanoleaf/button.py
|
||||
@@ -835,7 +827,6 @@ omit =
|
||||
homeassistant/components/nibe_heatpump/__init__.py
|
||||
homeassistant/components/nibe_heatpump/climate.py
|
||||
homeassistant/components/nibe_heatpump/binary_sensor.py
|
||||
homeassistant/components/nibe_heatpump/number.py
|
||||
homeassistant/components/nibe_heatpump/select.py
|
||||
homeassistant/components/nibe_heatpump/sensor.py
|
||||
homeassistant/components/nibe_heatpump/switch.py
|
||||
@@ -964,6 +955,7 @@ omit =
|
||||
homeassistant/components/ping/__init__.py
|
||||
homeassistant/components/ping/binary_sensor.py
|
||||
homeassistant/components/ping/device_tracker.py
|
||||
homeassistant/components/ping/helpers.py
|
||||
homeassistant/components/pioneer/media_player.py
|
||||
homeassistant/components/plaato/__init__.py
|
||||
homeassistant/components/plaato/binary_sensor.py
|
||||
@@ -1122,7 +1114,6 @@ omit =
|
||||
homeassistant/components/sesame/lock.py
|
||||
homeassistant/components/seven_segments/image_processing.py
|
||||
homeassistant/components/seventeentrack/sensor.py
|
||||
homeassistant/components/shiftr/*
|
||||
homeassistant/components/shodan/sensor.py
|
||||
homeassistant/components/sia/__init__.py
|
||||
homeassistant/components/sia/alarm_control_panel.py
|
||||
@@ -1301,6 +1292,7 @@ omit =
|
||||
homeassistant/components/system_bridge/__init__.py
|
||||
homeassistant/components/system_bridge/binary_sensor.py
|
||||
homeassistant/components/system_bridge/coordinator.py
|
||||
homeassistant/components/system_bridge/media_player.py
|
||||
homeassistant/components/system_bridge/notify.py
|
||||
homeassistant/components/system_bridge/sensor.py
|
||||
homeassistant/components/systemmonitor/sensor.py
|
||||
@@ -1400,6 +1392,7 @@ omit =
|
||||
homeassistant/components/trafikverket_weatherstation/coordinator.py
|
||||
homeassistant/components/trafikverket_weatherstation/sensor.py
|
||||
homeassistant/components/transmission/__init__.py
|
||||
homeassistant/components/transmission/coordinator.py
|
||||
homeassistant/components/transmission/sensor.py
|
||||
homeassistant/components/transmission/switch.py
|
||||
homeassistant/components/travisci/sensor.py
|
||||
@@ -1474,7 +1467,9 @@ omit =
|
||||
homeassistant/components/vicare/binary_sensor.py
|
||||
homeassistant/components/vicare/button.py
|
||||
homeassistant/components/vicare/climate.py
|
||||
homeassistant/components/vicare/entity.py
|
||||
homeassistant/components/vicare/sensor.py
|
||||
homeassistant/components/vicare/utils.py
|
||||
homeassistant/components/vicare/water_heater.py
|
||||
homeassistant/components/vilfo/__init__.py
|
||||
homeassistant/components/vilfo/sensor.py
|
||||
@@ -1516,7 +1511,6 @@ omit =
|
||||
homeassistant/components/wiffi/sensor.py
|
||||
homeassistant/components/wiffi/wiffi_strings.py
|
||||
homeassistant/components/wirelesstag/*
|
||||
homeassistant/components/withings/api.py
|
||||
homeassistant/components/wolflink/__init__.py
|
||||
homeassistant/components/wolflink/sensor.py
|
||||
homeassistant/components/worldtidesinfo/sensor.py
|
||||
|
||||
18
.github/workflows/builder.yml
vendored
18
.github/workflows/builder.yml
vendored
@@ -24,12 +24,12 @@ jobs:
|
||||
publish: ${{ steps.version.outputs.publish }}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -56,10 +56,10 @@ jobs:
|
||||
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Download nightly wheels of frontend
|
||||
if: needs.init.outputs.channel == 'dev'
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
if: needs.init.outputs.channel == 'dev'
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
@@ -252,7 +252,7 @@ jobs:
|
||||
- green
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Set build additional args
|
||||
run: |
|
||||
@@ -289,7 +289,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Initialize git
|
||||
uses: home-assistant/actions/helpers/git-init@master
|
||||
@@ -327,7 +327,7 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.1.2
|
||||
|
||||
60
.github/workflows/ci.yaml
vendored
60
.github/workflows/ci.yaml
vendored
@@ -37,18 +37,20 @@ env:
|
||||
PIP_CACHE_VERSION: 4
|
||||
MYPY_CACHE_VERSION: 5
|
||||
BLACK_CACHE_VERSION: 1
|
||||
HA_SHORT_VERSION: "2023.10"
|
||||
HA_SHORT_VERSION: "2023.11"
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
ALL_PYTHON_VERSIONS: "['3.11']"
|
||||
ALL_PYTHON_VERSIONS: "['3.11', '3.12']"
|
||||
# 10.3 is the oldest supported version
|
||||
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
|
||||
# 10.6 is the current long-term-support
|
||||
# - 10.6.10 is the version currently shipped with the Add-on (as of 31 Jan 2023)
|
||||
# 10.10 is the latest short-term-support
|
||||
# - 10.10.3 is the latest (as of 6 Feb 2023)
|
||||
# 10.11 is the latest long-term-support
|
||||
# - 10.11.2 is the version currently shipped with Synology (as of 11 Oct 2023)
|
||||
# mysql 8.0.32 does not always behave the same as MariaDB
|
||||
# and some queries that work on MariaDB do not work on MySQL
|
||||
MARIADB_VERSIONS: "['mariadb:10.3.32','mariadb:10.6.10','mariadb:10.10.3','mysql:8.0.32']"
|
||||
MARIADB_VERSIONS: "['mariadb:10.3.32','mariadb:10.6.10','mariadb:10.10.3','mariadb:10.11.2','mysql:8.0.32']"
|
||||
# 12 is the oldest supported version
|
||||
# - 12.14 is the latest (as of 9 Feb 2023)
|
||||
# 15 is the latest version
|
||||
@@ -89,7 +91,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Generate partial Python venv restore key
|
||||
id: generate_python_cache_key
|
||||
run: >-
|
||||
@@ -222,10 +224,10 @@ jobs:
|
||||
- info
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -267,9 +269,9 @@ jobs:
|
||||
- pre-commit
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
@@ -335,9 +337,9 @@ jobs:
|
||||
- pre-commit
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
@@ -384,9 +386,9 @@ jobs:
|
||||
- pre-commit
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
@@ -478,10 +480,10 @@ jobs:
|
||||
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -546,10 +548,10 @@ jobs:
|
||||
- base
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -578,10 +580,10 @@ jobs:
|
||||
- base
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -611,10 +613,10 @@ jobs:
|
||||
- base
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -655,10 +657,10 @@ jobs:
|
||||
- base
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
check-latest: true
|
||||
@@ -737,10 +739,10 @@ jobs:
|
||||
bluez \
|
||||
ffmpeg
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -889,10 +891,10 @@ jobs:
|
||||
ffmpeg \
|
||||
libmariadb-dev-compat
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -1013,10 +1015,10 @@ jobs:
|
||||
ffmpeg \
|
||||
postgresql-server-dev-14
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
@@ -1108,7 +1110,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Download all coverage artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Upload coverage to Codecov (full coverage)
|
||||
|
||||
39
.github/workflows/codeql.yml
vendored
Normal file
39
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: "CodeQL"
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- rc
|
||||
- master
|
||||
schedule:
|
||||
- cron: "30 18 * * 4"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 360
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2.22.3
|
||||
with:
|
||||
languages: python
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2.22.3
|
||||
with:
|
||||
category: "/language:python"
|
||||
4
.github/workflows/translations.yml
vendored
4
.github/workflows/translations.yml
vendored
@@ -19,10 +19,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v4.7.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
|
||||
51
.github/workflows/wheels.yml
vendored
51
.github/workflows/wheels.yml
vendored
@@ -10,8 +10,10 @@ on:
|
||||
- dev
|
||||
- rc
|
||||
paths:
|
||||
- "requirements.txt"
|
||||
- ".github/workflows/wheels.yml"
|
||||
- "homeassistant/package_constraints.txt"
|
||||
- "requirements_all.txt"
|
||||
- "requirements.txt"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name}}
|
||||
@@ -26,7 +28,7 @@ jobs:
|
||||
architectures: ${{ steps.info.outputs.architectures }}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Get information
|
||||
id: info
|
||||
@@ -80,11 +82,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
abi: ["cp311"]
|
||||
abi: ["cp311", "cp312"]
|
||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Download env_file
|
||||
uses: actions/download-artifact@v3
|
||||
@@ -97,7 +99,7 @@ jobs:
|
||||
name: requirements_diff
|
||||
|
||||
- name: Build wheels
|
||||
uses: home-assistant/wheels@2023.09.1
|
||||
uses: home-assistant/wheels@2023.10.5
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
@@ -110,7 +112,7 @@ jobs:
|
||||
requirements-diff: "requirements_diff.txt"
|
||||
requirements: "requirements.txt"
|
||||
|
||||
integrations_cp311:
|
||||
integrations:
|
||||
name: Build wheels ${{ matrix.abi }} for ${{ matrix.arch }}
|
||||
if: github.repository_owner == 'home-assistant'
|
||||
needs: init
|
||||
@@ -118,11 +120,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
abi: ["cp311"]
|
||||
abi: ["cp311", "cp312"]
|
||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4.1.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Download env_file
|
||||
uses: actions/download-artifact@v3
|
||||
@@ -168,6 +170,18 @@ jobs:
|
||||
|
||||
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all.txt requirements_all.txt
|
||||
|
||||
- name: Create requirements for cython<3
|
||||
run: |
|
||||
# Some dependencies still require 'cython<3'
|
||||
# and don't yet use isolated build environments.
|
||||
# Build these first.
|
||||
# grpcio: https://github.com/grpc/grpc/issues/33918
|
||||
# pydantic: https://github.com/pydantic/pydantic/issues/7689
|
||||
|
||||
touch requirements_old-cython.txt
|
||||
cat homeassistant/package_constraints.txt | grep 'grpcio==' >> requirements_old-cython.txt
|
||||
cat homeassistant/package_constraints.txt | grep 'pydantic==' >> requirements_old-cython.txt
|
||||
|
||||
- name: Adjust build env
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" = "i386" ]; then
|
||||
@@ -177,8 +191,23 @@ jobs:
|
||||
# Do not pin numpy in wheels building
|
||||
sed -i "/numpy/d" homeassistant/package_constraints.txt
|
||||
|
||||
- name: Build wheels (old cython)
|
||||
uses: home-assistant/wheels@2023.10.5
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
arch: ${{ matrix.arch }}
|
||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||
env-file: true
|
||||
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev"
|
||||
skip-binary: aiohttp;charset-normalizer;grpcio;SQLAlchemy;protobuf
|
||||
constraints: "homeassistant/package_constraints.txt"
|
||||
requirements-diff: "requirements_diff.txt"
|
||||
requirements: "requirements_old-cython.txt"
|
||||
pip: "'cython<3'"
|
||||
|
||||
- name: Build wheels (part 1)
|
||||
uses: home-assistant/wheels@2023.09.1
|
||||
uses: home-assistant/wheels@2023.10.5
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
@@ -192,7 +221,7 @@ jobs:
|
||||
requirements: "requirements_all.txtaa"
|
||||
|
||||
- name: Build wheels (part 2)
|
||||
uses: home-assistant/wheels@2023.09.1
|
||||
uses: home-assistant/wheels@2023.10.5
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
@@ -206,7 +235,7 @@ jobs:
|
||||
requirements: "requirements_all.txtab"
|
||||
|
||||
- name: Build wheels (part 3)
|
||||
uses: home-assistant/wheels@2023.09.1
|
||||
uses: home-assistant/wheels@2023.10.5
|
||||
with:
|
||||
abi: ${{ matrix.abi }}
|
||||
tag: musllinux_1_2
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -111,9 +111,6 @@ virtualization/vagrant/config
|
||||
!.vscode/tasks.json
|
||||
.env
|
||||
|
||||
# Built docs
|
||||
docs/build
|
||||
|
||||
# Windows Explorer
|
||||
desktop.ini
|
||||
/home-assistant.pyproj
|
||||
|
||||
@@ -3,3 +3,4 @@ ignored:
|
||||
- DL3008
|
||||
- DL3013
|
||||
- DL3018
|
||||
- DL3042
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.0.289
|
||||
rev: v0.1.1
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
- --fix
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.9.1
|
||||
rev: 23.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
*.md
|
||||
.strict-typing
|
||||
azure-*.yml
|
||||
docs/source/_templates/*
|
||||
homeassistant/components/*/translations/*.json
|
||||
homeassistant/generated/*
|
||||
tests/components/lidarr/fixtures/initialize.js
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# .readthedocs.yml
|
||||
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: setuptools
|
||||
path: .
|
||||
- requirements: requirements_docs.txt
|
||||
@@ -103,6 +103,7 @@ homeassistant.components.devolo_home_control.*
|
||||
homeassistant.components.devolo_home_network.*
|
||||
homeassistant.components.dhcp.*
|
||||
homeassistant.components.diagnostics.*
|
||||
homeassistant.components.discovergy.*
|
||||
homeassistant.components.dlna_dmr.*
|
||||
homeassistant.components.dnsip.*
|
||||
homeassistant.components.doorbird.*
|
||||
@@ -156,15 +157,7 @@ homeassistant.components.homeassistant_green.*
|
||||
homeassistant.components.homeassistant_hardware.*
|
||||
homeassistant.components.homeassistant_sky_connect.*
|
||||
homeassistant.components.homeassistant_yellow.*
|
||||
homeassistant.components.homekit
|
||||
homeassistant.components.homekit.accessories
|
||||
homeassistant.components.homekit.aidmanager
|
||||
homeassistant.components.homekit.config_flow
|
||||
homeassistant.components.homekit.diagnostics
|
||||
homeassistant.components.homekit.logbook
|
||||
homeassistant.components.homekit.type_locks
|
||||
homeassistant.components.homekit.type_triggers
|
||||
homeassistant.components.homekit.util
|
||||
homeassistant.components.homekit.*
|
||||
homeassistant.components.homekit_controller
|
||||
homeassistant.components.homekit_controller.alarm_control_panel
|
||||
homeassistant.components.homekit_controller.button
|
||||
@@ -327,6 +320,7 @@ homeassistant.components.synology_dsm.*
|
||||
homeassistant.components.systemmonitor.*
|
||||
homeassistant.components.tag.*
|
||||
homeassistant.components.tailscale.*
|
||||
homeassistant.components.tami4.*
|
||||
homeassistant.components.tautulli.*
|
||||
homeassistant.components.tcp.*
|
||||
homeassistant.components.text.*
|
||||
@@ -343,6 +337,7 @@ homeassistant.components.trafikverket_camera.*
|
||||
homeassistant.components.trafikverket_ferry.*
|
||||
homeassistant.components.trafikverket_train.*
|
||||
homeassistant.components.trafikverket_weatherstation.*
|
||||
homeassistant.components.transmission.*
|
||||
homeassistant.components.trend.*
|
||||
homeassistant.components.tts.*
|
||||
homeassistant.components.twentemilieu.*
|
||||
@@ -366,6 +361,7 @@ homeassistant.components.webostv.*
|
||||
homeassistant.components.websocket_api.*
|
||||
homeassistant.components.wemo.*
|
||||
homeassistant.components.whois.*
|
||||
homeassistant.components.withings.*
|
||||
homeassistant.components.wiz.*
|
||||
homeassistant.components.wled.*
|
||||
homeassistant.components.worldclock.*
|
||||
|
||||
6
.vscode/tasks.json
vendored
6
.vscode/tasks.json
vendored
@@ -16,7 +16,7 @@
|
||||
{
|
||||
"label": "Pytest",
|
||||
"type": "shell",
|
||||
"command": "pytest --timeout=10 tests",
|
||||
"command": "python3 -m pytest --timeout=10 tests",
|
||||
"dependsOn": ["Install all Test Requirements"],
|
||||
"group": {
|
||||
"kind": "test",
|
||||
@@ -31,7 +31,7 @@
|
||||
{
|
||||
"label": "Pytest (changed tests only)",
|
||||
"type": "shell",
|
||||
"command": "pytest --timeout=10 --picked",
|
||||
"command": "python3 -m pytest --timeout=10 --picked",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
@@ -75,7 +75,7 @@
|
||||
"label": "Code Coverage",
|
||||
"detail": "Generate code coverage report for a given integration.",
|
||||
"type": "shell",
|
||||
"command": "pytest ./tests/components/${input:integrationName}/ --cov=homeassistant.components.${input:integrationName} --cov-report term-missing --durations-min=1 --durations=0 --numprocesses=auto",
|
||||
"command": "python3 -m pytest ./tests/components/${input:integrationName}/ --cov=homeassistant.components.${input:integrationName} --cov-report term-missing --durations-min=1 --durations=0 --numprocesses=auto",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
|
||||
40
CODEOWNERS
40
CODEOWNERS
@@ -100,8 +100,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/apprise/ @caronc
|
||||
/homeassistant/components/aprs/ @PhilRW
|
||||
/tests/components/aprs/ @PhilRW
|
||||
/homeassistant/components/aranet/ @aschmitz
|
||||
/tests/components/aranet/ @aschmitz
|
||||
/homeassistant/components/aranet/ @aschmitz @thecode
|
||||
/tests/components/aranet/ @aschmitz @thecode
|
||||
/homeassistant/components/arcam_fmj/ @elupus
|
||||
/tests/components/arcam_fmj/ @elupus
|
||||
/homeassistant/components/arris_tg2492lg/ @vanbalken
|
||||
@@ -233,8 +233,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/counter/ @fabaff
|
||||
/homeassistant/components/cover/ @home-assistant/core
|
||||
/tests/components/cover/ @home-assistant/core
|
||||
/homeassistant/components/cpuspeed/ @fabaff @frenck
|
||||
/tests/components/cpuspeed/ @fabaff @frenck
|
||||
/homeassistant/components/cpuspeed/ @fabaff
|
||||
/tests/components/cpuspeed/ @fabaff
|
||||
/homeassistant/components/crownstone/ @Crownstone @RicArch97
|
||||
/tests/components/crownstone/ @Crownstone @RicArch97
|
||||
/homeassistant/components/cups/ @fabaff
|
||||
@@ -660,8 +660,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/kmtronic/ @dgomes
|
||||
/homeassistant/components/knx/ @Julius2342 @farmio @marvin-w
|
||||
/tests/components/knx/ @Julius2342 @farmio @marvin-w
|
||||
/homeassistant/components/kodi/ @OnFreund @cgtobi
|
||||
/tests/components/kodi/ @OnFreund @cgtobi
|
||||
/homeassistant/components/kodi/ @OnFreund
|
||||
/tests/components/kodi/ @OnFreund
|
||||
/homeassistant/components/konnected/ @heythisisnate
|
||||
/tests/components/konnected/ @heythisisnate
|
||||
/homeassistant/components/kostal_plenticore/ @stegm
|
||||
@@ -755,8 +755,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/melissa/ @kennedyshead
|
||||
/homeassistant/components/melnor/ @vanstinator
|
||||
/tests/components/melnor/ @vanstinator
|
||||
/homeassistant/components/met/ @danielhiversen @thimic
|
||||
/tests/components/met/ @danielhiversen @thimic
|
||||
/homeassistant/components/met/ @danielhiversen
|
||||
/tests/components/met/ @danielhiversen
|
||||
/homeassistant/components/met_eireann/ @DylanGore
|
||||
/tests/components/met_eireann/ @DylanGore
|
||||
/homeassistant/components/meteo_france/ @hacf-fr @oncleben31 @Quentame
|
||||
@@ -949,6 +949,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/picnic/ @corneyl
|
||||
/homeassistant/components/pilight/ @trekky12
|
||||
/tests/components/pilight/ @trekky12
|
||||
/homeassistant/components/ping/ @jpbede
|
||||
/tests/components/ping/ @jpbede
|
||||
/homeassistant/components/plaato/ @JohNan
|
||||
/tests/components/plaato/ @JohNan
|
||||
/homeassistant/components/plex/ @jjlawren
|
||||
@@ -1063,8 +1065,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/roborock/ @humbertogontijo @Lash-L
|
||||
/homeassistant/components/roku/ @ctalkington
|
||||
/tests/components/roku/ @ctalkington
|
||||
/homeassistant/components/roomba/ @pschmitt @cyr-ius @shenxn
|
||||
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn
|
||||
/homeassistant/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1
|
||||
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1
|
||||
/homeassistant/components/roon/ @pavoni
|
||||
/tests/components/roon/ @pavoni
|
||||
/homeassistant/components/rpi_power/ @shenxn @swetoast
|
||||
@@ -1189,8 +1191,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/sonarr/ @ctalkington
|
||||
/homeassistant/components/songpal/ @rytilahti @shenxn
|
||||
/tests/components/songpal/ @rytilahti @shenxn
|
||||
/homeassistant/components/sonos/ @cgtobi @jjlawren
|
||||
/tests/components/sonos/ @cgtobi @jjlawren
|
||||
/homeassistant/components/sonos/ @jjlawren
|
||||
/tests/components/sonos/ @jjlawren
|
||||
/homeassistant/components/soundtouch/ @kroimon
|
||||
/tests/components/soundtouch/ @kroimon
|
||||
/homeassistant/components/spaceapi/ @fabaff
|
||||
@@ -1265,6 +1267,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/tag/ @balloob @dmulcahey
|
||||
/homeassistant/components/tailscale/ @frenck
|
||||
/tests/components/tailscale/ @frenck
|
||||
/homeassistant/components/tami4/ @Guy293
|
||||
/tests/components/tami4/ @Guy293
|
||||
/homeassistant/components/tankerkoenig/ @guillempages @mib1185
|
||||
/tests/components/tankerkoenig/ @guillempages @mib1185
|
||||
/homeassistant/components/tapsaff/ @bazwilliams
|
||||
@@ -1321,10 +1325,10 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/trafikverket_camera/ @gjohansson-ST
|
||||
/homeassistant/components/trafikverket_ferry/ @gjohansson-ST
|
||||
/tests/components/trafikverket_ferry/ @gjohansson-ST
|
||||
/homeassistant/components/trafikverket_train/ @endor-force @gjohansson-ST
|
||||
/tests/components/trafikverket_train/ @endor-force @gjohansson-ST
|
||||
/homeassistant/components/trafikverket_weatherstation/ @endor-force @gjohansson-ST
|
||||
/tests/components/trafikverket_weatherstation/ @endor-force @gjohansson-ST
|
||||
/homeassistant/components/trafikverket_train/ @gjohansson-ST
|
||||
/tests/components/trafikverket_train/ @gjohansson-ST
|
||||
/homeassistant/components/trafikverket_weatherstation/ @gjohansson-ST
|
||||
/tests/components/trafikverket_weatherstation/ @gjohansson-ST
|
||||
/homeassistant/components/transmission/ @engrbm87 @JPHutchins
|
||||
/tests/components/transmission/ @engrbm87 @JPHutchins
|
||||
/homeassistant/components/trend/ @jpbede
|
||||
@@ -1436,8 +1440,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/wilight/ @leofig-rj
|
||||
/tests/components/wilight/ @leofig-rj
|
||||
/homeassistant/components/wirelesstag/ @sergeymaysak
|
||||
/homeassistant/components/withings/ @vangorra @joostlek
|
||||
/tests/components/withings/ @vangorra @joostlek
|
||||
/homeassistant/components/withings/ @joostlek
|
||||
/tests/components/withings/ @joostlek
|
||||
/homeassistant/components/wiz/ @sbidy
|
||||
/tests/components/wiz/ @sbidy
|
||||
/homeassistant/components/wled/ @frenck
|
||||
|
||||
16
Dockerfile
16
Dockerfile
@@ -14,41 +14,29 @@ COPY requirements.txt homeassistant/
|
||||
COPY homeassistant/package_constraints.txt homeassistant/homeassistant/
|
||||
RUN \
|
||||
pip3 install \
|
||||
--no-cache-dir \
|
||||
--only-binary=:all: \
|
||||
--index-url "https://wheels.home-assistant.io/musllinux-index/" \
|
||||
-r homeassistant/requirements.txt
|
||||
|
||||
COPY requirements_all.txt home_assistant_frontend-* home_assistant_intents-* homeassistant/
|
||||
RUN \
|
||||
if ls homeassistant/home_assistant_frontend*.whl 1> /dev/null 2>&1; then \
|
||||
pip3 install \
|
||||
--no-cache-dir \
|
||||
--no-index \
|
||||
homeassistant/home_assistant_frontend-*.whl; \
|
||||
pip3 install homeassistant/home_assistant_frontend-*.whl; \
|
||||
fi \
|
||||
&& if ls homeassistant/home_assistant_intents*.whl 1> /dev/null 2>&1; then \
|
||||
pip3 install \
|
||||
--no-cache-dir \
|
||||
--no-index \
|
||||
homeassistant/home_assistant_intents-*.whl; \
|
||||
pip3 install homeassistant/home_assistant_intents-*.whl; \
|
||||
fi \
|
||||
&& \
|
||||
LD_PRELOAD="/usr/local/lib/libjemalloc.so.2" \
|
||||
MALLOC_CONF="background_thread:true,metadata_thp:auto,dirty_decay_ms:20000,muzzy_decay_ms:20000" \
|
||||
pip3 install \
|
||||
--no-cache-dir \
|
||||
--only-binary=:all: \
|
||||
--index-url "https://wheels.home-assistant.io/musllinux-index/" \
|
||||
-r homeassistant/requirements_all.txt
|
||||
|
||||
## Setup Home Assistant Core
|
||||
COPY . homeassistant/
|
||||
RUN \
|
||||
pip3 install \
|
||||
--no-cache-dir \
|
||||
--only-binary=:all: \
|
||||
--index-url "https://wheels.home-assistant.io/musllinux-index/" \
|
||||
-e ./homeassistant \
|
||||
&& python3 -m compileall \
|
||||
homeassistant/homeassistant
|
||||
|
||||
10
build.yaml
10
build.yaml
@@ -1,10 +1,10 @@
|
||||
image: ghcr.io/home-assistant/{arch}-homeassistant
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2023.09.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2023.09.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2023.09.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2023.09.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2023.09.0
|
||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2023.10.0
|
||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2023.10.0
|
||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2023.10.0
|
||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2023.10.0
|
||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2023.10.0
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
|
||||
230
docs/Makefile
230
docs/Makefile
@@ -1,230 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " livehtml to make standalone HTML files via sphinx-autobuild"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " applehelp to make an Apple Help Book"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " epub3 to make an epub3"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||
@echo " dummy to check syntax errors of document sources"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
.PHONY: livehtml
|
||||
livehtml:
|
||||
sphinx-autobuild -z ../homeassistant/ --port 0 -B -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
|
||||
.PHONY: dirhtml
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
.PHONY: singlehtml
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
.PHONY: pickle
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
.PHONY: json
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
.PHONY: htmlhelp
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
.PHONY: qthelp
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Home-Assistant.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Home-Assistant.qhc"
|
||||
|
||||
.PHONY: applehelp
|
||||
applehelp:
|
||||
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||
@echo
|
||||
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||
"~/Library/Documentation/Help or install it in your application" \
|
||||
"bundle."
|
||||
|
||||
.PHONY: devhelp
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Home-Assistant"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Home-Assistant"
|
||||
@echo "# devhelp"
|
||||
|
||||
.PHONY: epub
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
.PHONY: epub3
|
||||
epub3:
|
||||
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
|
||||
@echo
|
||||
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
|
||||
|
||||
.PHONY: latex
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
.PHONY: latexpdf
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: latexpdfja
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: text
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
.PHONY: man
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
.PHONY: texinfo
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
.PHONY: gettext
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
.PHONY: changes
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
.PHONY: linkcheck
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
.PHONY: doctest
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||
@echo "Testing of coverage in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/coverage/python.txt."
|
||||
|
||||
.PHONY: xml
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
.PHONY: pseudoxml
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
|
||||
.PHONY: dummy
|
||||
dummy:
|
||||
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
|
||||
@echo
|
||||
@echo "Build finished. Dummy builder generates no files."
|
||||
0
docs/build/.empty
vendored
0
docs/build/.empty
vendored
281
docs/make.bat
281
docs/make.bat
@@ -1,281 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% source
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. epub3 to make an epub3
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. xml to make Docutils-native XML files
|
||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
echo. coverage to run coverage check of the documentation if enabled
|
||||
echo. dummy to check syntax errors of document sources
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
REM Check if sphinx-build is available and fallback to Python version if any
|
||||
%SPHINXBUILD% 1>NUL 2>NUL
|
||||
if errorlevel 9009 goto sphinx_python
|
||||
goto sphinx_ok
|
||||
|
||||
:sphinx_python
|
||||
|
||||
set SPHINXBUILD=python -m sphinx.__init__
|
||||
%SPHINXBUILD% 2> nul
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:sphinx_ok
|
||||
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Home-Assistant.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Home-Assistant.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub3" (
|
||||
%SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdf" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf
|
||||
cd %~dp0
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdfja" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf-ja
|
||||
cd %~dp0
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "coverage" (
|
||||
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of coverage in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/coverage/python.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "xml" (
|
||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pseudoxml" (
|
||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dummy" (
|
||||
%SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. Dummy builder generates no files.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 174 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 226 KiB |
@@ -1,45 +0,0 @@
|
||||
"""Sphinx extension for ReadTheDocs-style "Edit on GitHub" links on the sidebar.
|
||||
|
||||
Loosely based on https://github.com/astropy/astropy/pull/347
|
||||
"""
|
||||
|
||||
import os
|
||||
import warnings
|
||||
|
||||
__licence__ = "BSD (3 clause)"
|
||||
|
||||
|
||||
def get_github_url(app, view, path):
|
||||
"""Build the GitHub URL."""
|
||||
return (
|
||||
f"https://github.com/{app.config.edit_on_github_project}/"
|
||||
f"{view}/{app.config.edit_on_github_branch}/"
|
||||
f"{app.config.edit_on_github_src_path}{path}"
|
||||
)
|
||||
|
||||
|
||||
def html_page_context(app, pagename, templatename, context, doctree):
|
||||
"""Build the HTML page."""
|
||||
if templatename != "page.html":
|
||||
return
|
||||
|
||||
if not app.config.edit_on_github_project:
|
||||
warnings.warn("edit_on_github_project not specified")
|
||||
return
|
||||
if not doctree:
|
||||
warnings.warn("doctree is None")
|
||||
return
|
||||
path = os.path.relpath(doctree.get("source"), app.builder.srcdir)
|
||||
show_url = get_github_url(app, "blob", path)
|
||||
edit_url = get_github_url(app, "edit", path)
|
||||
|
||||
context["show_on_github_url"] = show_url
|
||||
context["edit_on_github_url"] = edit_url
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""Set up the app."""
|
||||
app.add_config_value("edit_on_github_project", "", True)
|
||||
app.add_config_value("edit_on_github_branch", "master", True)
|
||||
app.add_config_value("edit_on_github_src_path", "", True) # 'eg' "docs/"
|
||||
app.connect("html-page-context", html_page_context)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,6 +0,0 @@
|
||||
<ul>
|
||||
<li><a href="https://home-assistant.io/">Homepage</a></li>
|
||||
<li><a href="https://community.home-assistant.io">Community Forums</a></li>
|
||||
<li><a href="https://github.com/home-assistant/core">GitHub</a></li>
|
||||
<li><a href="https://discord.gg/c5DvZ4e">Discord</a></li>
|
||||
</ul>
|
||||
@@ -1,13 +0,0 @@
|
||||
{%- if show_source and has_source and sourcename %}
|
||||
<h3>{{ _('This Page') }}</h3>
|
||||
<ul class="this-page-menu">
|
||||
{%- if show_on_github_url %}
|
||||
<li><a href="{{ show_on_github_url }}"
|
||||
rel="nofollow">{{ _('Show on GitHub') }}</a></li>
|
||||
{%- endif %}
|
||||
{%- if edit_on_github_url %}
|
||||
<li><a href="{{ edit_on_github_url }}"
|
||||
rel="nofollow">{{ _('Edit on GitHub') }}</a></li>
|
||||
{%- endif %}
|
||||
</ul>
|
||||
{%- endif %}
|
||||
@@ -1,29 +0,0 @@
|
||||
:mod:`homeassistant.auth`
|
||||
=========================
|
||||
|
||||
.. automodule:: homeassistant.auth
|
||||
:members:
|
||||
|
||||
homeassistant.auth.auth\_store
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.auth.auth_store
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.auth.const
|
||||
------------------------
|
||||
|
||||
.. automodule:: homeassistant.auth.const
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.auth.models
|
||||
-------------------------
|
||||
|
||||
.. automodule:: homeassistant.auth.models
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _bootstrap_module:
|
||||
|
||||
:mod:`homeassistant.bootstrap`
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.bootstrap
|
||||
:members:
|
||||
@@ -1,170 +0,0 @@
|
||||
:mod:`homeassistant.components`
|
||||
===============================
|
||||
|
||||
air\_quality
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.air_quality
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
alarm\_control\_panel
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.alarm_control_panel
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
binary\_sensor
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.binary_sensor
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
camera
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.camera
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
calendar
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.calendar
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
climate
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.climate
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
conversation
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.conversation
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
cover
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.cover
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
device\_tracker
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.device_tracker
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
fan
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.fan
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
light
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.light
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
lock
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.lock
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
media\_player
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.media_player
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
notify
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.notify
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
remote
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.remote
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
switch
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.switch
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
sensor
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.sensor
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
vacuum
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.vacuum
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
water\_heater
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.water_heater
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
weather
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.weather
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
webhook
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.components.webhook
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _config_entries_module:
|
||||
|
||||
:mod:`homeassistant.config_entries`
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: homeassistant.config_entries
|
||||
:members:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _core_module:
|
||||
|
||||
:mod:`homeassistant.core`
|
||||
-------------------------
|
||||
|
||||
.. automodule:: homeassistant.core
|
||||
:members:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _data_entry_flow_module:
|
||||
|
||||
:mod:`homeassistant.data_entry_flow`
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.data_entry_flow
|
||||
:members:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _exceptions_module:
|
||||
|
||||
:mod:`homeassistant.exceptions`
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: homeassistant.exceptions
|
||||
:members:
|
||||
@@ -1,335 +0,0 @@
|
||||
:mod:`homeassistant.helpers`
|
||||
============================
|
||||
|
||||
.. automodule:: homeassistant.helpers
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.aiohttp\_client
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.aiohttp_client
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.area\_registry
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.area_registry
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.check\_config
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.check_config
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.collection
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.collection
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.condition
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.condition
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.config\_entry\_flow
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.config_entry_flow
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.config\_entry\_oauth2\_flow
|
||||
-------------------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.config_entry_oauth2_flow
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.config\_validation
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.config_validation
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.data\_entry\_flow
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.data_entry_flow
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.debounce
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.debounce
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.deprecation
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.deprecation
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.device\_registry
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.device_registry
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.discovery
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.discovery
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.dispatcher
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.dispatcher
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entity
|
||||
----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entity
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entity\_component
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entity_component
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entity\_platform
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entity_platform
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entity\_registry
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entity_registry
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entity\_values
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entity_values
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.entityfilter
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.entityfilter
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.event
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.event
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.icon
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.icon
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.integration\_platform
|
||||
-------------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.integration_platform
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.intent
|
||||
----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.intent
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.json
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.json
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.location
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.location
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.logging
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.logging
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.network
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.network
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.restore\_state
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.restore_state
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.script
|
||||
----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.script
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.service
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.service
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.signal
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.signal
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.state
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.state
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.storage
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.storage
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.sun
|
||||
-------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.sun
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.system\_info
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.system_info
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.temperature
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.temperature
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.template
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.template
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.translation
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.translation
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.typing
|
||||
----------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.typing
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.helpers.update\_coordinator
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: homeassistant.helpers.update_coordinator
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _loader_module:
|
||||
|
||||
:mod:`homeassistant.loader`
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.loader
|
||||
:members:
|
||||
@@ -1,151 +0,0 @@
|
||||
:mod:`homeassistant.util`
|
||||
=========================
|
||||
|
||||
.. automodule:: homeassistant.util
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.yaml
|
||||
-----------------------
|
||||
|
||||
.. automodule:: homeassistant.util.yaml
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.aiohttp
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.aiohttp
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.async\_
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.async_
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.color
|
||||
------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.color
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.decorator
|
||||
----------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.decorator
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.distance
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.distance
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.dt
|
||||
---------------------
|
||||
|
||||
.. automodule:: homeassistant.util.dt
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.json
|
||||
-----------------------
|
||||
|
||||
.. automodule:: homeassistant.util.json
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.location
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.location
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.logging
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.logging
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.network
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.network
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.package
|
||||
--------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.package
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.pil
|
||||
----------------------
|
||||
|
||||
.. automodule:: homeassistant.util.pil
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.pressure
|
||||
---------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.pressure
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.ssl
|
||||
----------------------
|
||||
|
||||
.. automodule:: homeassistant.util.ssl
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.temperature
|
||||
------------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.temperature
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.unit\_system
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.unit_system
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
homeassistant.util.volume
|
||||
-------------------------
|
||||
|
||||
.. automodule:: homeassistant.util.volume
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,438 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Home Assistant documentation build configuration file.
|
||||
|
||||
This file is execfile()d with the current directory set to its
|
||||
containing dir.
|
||||
|
||||
Note that not all possible configuration values are present in this
|
||||
autogenerated file.
|
||||
|
||||
All configuration values have a default; values that are commented out
|
||||
serve to show the default.
|
||||
|
||||
If extensions (or modules to document with autodoc) are in another directory,
|
||||
add these directories to sys.path here. If the directory is relative to the
|
||||
documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
from homeassistant.const import __short_version__, __version__
|
||||
|
||||
PROJECT_NAME = "Home Assistant"
|
||||
PROJECT_PACKAGE_NAME = "homeassistant"
|
||||
PROJECT_AUTHOR = "The Home Assistant Authors"
|
||||
PROJECT_COPYRIGHT = PROJECT_AUTHOR
|
||||
PROJECT_LONG_DESCRIPTION = (
|
||||
"Home Assistant is an open-source "
|
||||
"home automation platform running on Python 3. "
|
||||
"Track and control all devices at home and "
|
||||
"automate control. "
|
||||
"Installation in less than a minute."
|
||||
)
|
||||
PROJECT_GITHUB_USERNAME = "home-assistant"
|
||||
PROJECT_GITHUB_REPOSITORY = "home-assistant"
|
||||
|
||||
GITHUB_PATH = f"{PROJECT_GITHUB_USERNAME}/{PROJECT_GITHUB_REPOSITORY}"
|
||||
GITHUB_URL = f"https://github.com/{GITHUB_PATH}"
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.abspath("_ext"))
|
||||
sys.path.insert(0, os.path.abspath("../homeassistant"))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.linkcode",
|
||||
"sphinx_autodoc_annotation",
|
||||
"edit_on_github",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = ".rst"
|
||||
|
||||
# The encoding of source files.
|
||||
#
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = PROJECT_NAME
|
||||
copyright = PROJECT_COPYRIGHT
|
||||
author = PROJECT_AUTHOR
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = __short_version__
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = __version__
|
||||
|
||||
code_branch = "dev" if "dev" in __version__ else "master"
|
||||
|
||||
# Edit on Github config
|
||||
edit_on_github_project = GITHUB_PATH
|
||||
edit_on_github_branch = code_branch
|
||||
edit_on_github_src_path = "docs/source/"
|
||||
|
||||
|
||||
def linkcode_resolve(domain, info):
|
||||
"""Determine the URL corresponding to Python object."""
|
||||
if domain != "py":
|
||||
return None
|
||||
modname = info["module"]
|
||||
fullname = info["fullname"]
|
||||
submod = sys.modules.get(modname)
|
||||
if submod is None:
|
||||
return None
|
||||
obj = submod
|
||||
for part in fullname.split("."):
|
||||
try:
|
||||
obj = getattr(obj, part)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return None
|
||||
try:
|
||||
fn = inspect.getsourcefile(obj)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
fn = None
|
||||
if not fn:
|
||||
return None
|
||||
try:
|
||||
source, lineno = inspect.findsource(obj)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
lineno = None
|
||||
if lineno:
|
||||
linespec = "#L%d" % (lineno + 1)
|
||||
else:
|
||||
linespec = ""
|
||||
index = fn.find("/homeassistant/")
|
||||
if index == -1:
|
||||
index = 0
|
||||
|
||||
fn = fn[index:]
|
||||
|
||||
return f"{GITHUB_URL}/blob/{code_branch}/{fn}{linespec}"
|
||||
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#
|
||||
# today = ''
|
||||
#
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
# keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "alabaster"
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {
|
||||
"logo": "logo.png",
|
||||
"logo_name": PROJECT_NAME,
|
||||
"description": PROJECT_LONG_DESCRIPTION,
|
||||
"github_user": PROJECT_GITHUB_USERNAME,
|
||||
"github_repo": PROJECT_GITHUB_REPOSITORY,
|
||||
"github_type": "star",
|
||||
"github_banner": True,
|
||||
"touch_icon": "logo-apple.png",
|
||||
# 'fixed_sidebar': True, # Re-enable when we have more content
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents.
|
||||
# "<project> v<release> documentation" by default.
|
||||
#
|
||||
# html_title = 'Home-Assistant v0.27.0'
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#
|
||||
# html_logo = '_static/logo.png'
|
||||
|
||||
# The name of an image file (relative to this directory) to use as a favicon of
|
||||
# the docs.
|
||||
# This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#
|
||||
html_favicon = "_static/favicon.ico"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#
|
||||
# html_extra_path = []
|
||||
|
||||
# If not None, a 'Last updated on:' timestamp is inserted at every page
|
||||
# bottom, using the given strftime format.
|
||||
# The empty string is equivalent to '%b %d, %Y'.
|
||||
#
|
||||
html_last_updated_fmt = "%b %d, %Y"
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#
|
||||
html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#
|
||||
html_sidebars = {
|
||||
"**": [
|
||||
"about.html",
|
||||
"links.html",
|
||||
"searchbox.html",
|
||||
"sourcelink.html",
|
||||
"navigation.html",
|
||||
"relations.html",
|
||||
]
|
||||
}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
# html_file_suffix = None
|
||||
|
||||
# Language to be used for generating the HTML full-text search index.
|
||||
# Sphinx supports the following languages:
|
||||
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
|
||||
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
|
||||
#
|
||||
# html_search_language = 'en'
|
||||
|
||||
# A dictionary with options for the search language support, empty by default.
|
||||
# 'ja' uses this config value.
|
||||
# 'zh' user can custom change `jieba` dictionary path.
|
||||
#
|
||||
# html_search_options = {'type': 'default'}
|
||||
|
||||
# The name of a javascript file (relative to the configuration directory) that
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#
|
||||
# html_search_scorer = 'scorer.js'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = "Home-Assistantdoc"
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(
|
||||
master_doc,
|
||||
"home-assistant.tex",
|
||||
"Home Assistant Documentation",
|
||||
"Home Assistant Team",
|
||||
"manual",
|
||||
)
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#
|
||||
# latex_appendices = []
|
||||
|
||||
# It false, will not define \strong, \code, itleref, \crossref ... but only
|
||||
# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
|
||||
# packages.
|
||||
#
|
||||
# latex_keep_old_macro_names = True
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, "home-assistant", "Home Assistant Documentation", [author], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(
|
||||
master_doc,
|
||||
"Home-Assistant",
|
||||
"Home Assistant Documentation",
|
||||
author,
|
||||
"Home Assistant",
|
||||
"Open-source home automation platform.",
|
||||
"Miscellaneous",
|
||||
)
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#
|
||||
# texinfo_no_detailmenu = False
|
||||
@@ -1,22 +0,0 @@
|
||||
================================
|
||||
Home Assistant API Documentation
|
||||
================================
|
||||
|
||||
Public API documentation for `Home Assistant developers`_.
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
api/*
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. _Home Assistant developers: https://developers.home-assistant.io/
|
||||
@@ -5,6 +5,7 @@ import asyncio
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Mapping
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from typing import Any, cast
|
||||
|
||||
import jwt
|
||||
@@ -12,7 +13,6 @@ import jwt
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import auth_store, jwt_wrapper, models
|
||||
from .const import ACCESS_TOKEN_EXPIRATION, GROUP_ID_ADMIN
|
||||
@@ -505,12 +505,13 @@ class AuthManager:
|
||||
|
||||
self._store.async_log_refresh_token_usage(refresh_token, remote_ip)
|
||||
|
||||
now = dt_util.utcnow()
|
||||
now = int(time.time())
|
||||
expire_seconds = int(refresh_token.access_token_expiration.total_seconds())
|
||||
return jwt.encode(
|
||||
{
|
||||
"iss": refresh_token.id,
|
||||
"iat": now,
|
||||
"exp": now + refresh_token.access_token_expiration,
|
||||
"exp": now + expire_seconds,
|
||||
},
|
||||
refresh_token.jwt_key,
|
||||
algorithm="HS256",
|
||||
|
||||
@@ -50,7 +50,7 @@ class MultiFactorAuthModule:
|
||||
|
||||
Default is same as type
|
||||
"""
|
||||
return self.config.get(CONF_ID, self.type)
|
||||
return self.config.get(CONF_ID, self.type) # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
@@ -60,7 +60,7 @@ class MultiFactorAuthModule:
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the auth module."""
|
||||
return self.config.get(CONF_NAME, self.DEFAULT_TITLE)
|
||||
return self.config.get(CONF_NAME, self.DEFAULT_TITLE) # type: ignore[no-any-return]
|
||||
|
||||
# Implement by extending class
|
||||
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
"""Permission constants for the websocket API.
|
||||
|
||||
Separate file to avoid circular imports.
|
||||
"""
|
||||
"""Permission for events."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
from homeassistant.components.frontend import EVENT_PANELS_UPDATED
|
||||
from homeassistant.components.lovelace import EVENT_LOVELACE_UPDATED
|
||||
from homeassistant.components.persistent_notification import (
|
||||
EVENT_PERSISTENT_NOTIFICATIONS_UPDATED,
|
||||
)
|
||||
from homeassistant.components.recorder import (
|
||||
EVENT_RECORDER_5MIN_STATISTICS_GENERATED,
|
||||
EVENT_RECORDER_HOURLY_STATISTICS_GENERATED,
|
||||
)
|
||||
from homeassistant.components.shopping_list import EVENT_SHOPPING_LIST_UPDATED
|
||||
from homeassistant.const import (
|
||||
EVENT_COMPONENT_LOADED,
|
||||
EVENT_CORE_CONFIG_UPDATE,
|
||||
EVENT_LOVELACE_UPDATED,
|
||||
EVENT_PANELS_UPDATED,
|
||||
EVENT_RECORDER_5MIN_STATISTICS_GENERATED,
|
||||
EVENT_RECORDER_HOURLY_STATISTICS_GENERATED,
|
||||
EVENT_SERVICE_REGISTERED,
|
||||
EVENT_SERVICE_REMOVED,
|
||||
EVENT_SHOPPING_LIST_UPDATED,
|
||||
EVENT_STATE_CHANGED,
|
||||
EVENT_THEMES_UPDATED,
|
||||
)
|
||||
@@ -38,7 +30,6 @@ SUBSCRIBE_ALLOWLIST: Final[set[str]] = {
|
||||
EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
EVENT_LOVELACE_UPDATED,
|
||||
EVENT_PANELS_UPDATED,
|
||||
EVENT_PERSISTENT_NOTIFICATIONS_UPDATED,
|
||||
EVENT_RECORDER_5MIN_STATISTICS_GENERATED,
|
||||
EVENT_RECORDER_HOURLY_STATISTICS_GENERATED,
|
||||
EVENT_SERVICE_REGISTERED,
|
||||
@@ -109,4 +109,4 @@ def test_all(policy: CategoryType, key: str) -> bool:
|
||||
if not isinstance(all_policy, dict):
|
||||
return bool(all_policy)
|
||||
|
||||
return all_policy.get(key, False)
|
||||
return all_policy.get(key, False) # type: ignore[no-any-return]
|
||||
|
||||
@@ -67,7 +67,7 @@ class AuthProvider:
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the auth provider."""
|
||||
return self.config.get(CONF_NAME, self.DEFAULT_TITLE)
|
||||
return self.config.get(CONF_NAME, self.DEFAULT_TITLE) # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def support_mfa(self) -> bool:
|
||||
|
||||
279
homeassistant/backports/LICENSE.Python
Normal file
279
homeassistant/backports/LICENSE.Python
Normal file
@@ -0,0 +1,279 @@
|
||||
A. HISTORY OF THE SOFTWARE
|
||||
==========================
|
||||
|
||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||
Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands
|
||||
as a successor of a language called ABC. Guido remains Python's
|
||||
principal author, although it includes many contributions from others.
|
||||
|
||||
In 1995, Guido continued his work on Python at the Corporation for
|
||||
National Research Initiatives (CNRI, see https://www.cnri.reston.va.us)
|
||||
in Reston, Virginia where he released several versions of the
|
||||
software.
|
||||
|
||||
In May 2000, Guido and the Python core development team moved to
|
||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||
year, the PythonLabs team moved to Digital Creations, which became
|
||||
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
|
||||
https://www.python.org/psf/) was formed, a non-profit organization
|
||||
created specifically to own Python-related Intellectual Property.
|
||||
Zope Corporation was a sponsoring member of the PSF.
|
||||
|
||||
All Python releases are Open Source (see https://opensource.org for
|
||||
the Open Source Definition). Historically, most, but not all, Python
|
||||
releases have also been GPL-compatible; the table below summarizes
|
||||
the various releases.
|
||||
|
||||
Release Derived Year Owner GPL-
|
||||
from compatible? (1)
|
||||
|
||||
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||
1.6 1.5.2 2000 CNRI no
|
||||
2.0 1.6 2000 BeOpen.com no
|
||||
1.6.1 1.6 2001 CNRI yes (2)
|
||||
2.1 2.0+1.6.1 2001 PSF no
|
||||
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||
2.1.2 2.1.1 2002 PSF yes
|
||||
2.1.3 2.1.2 2002 PSF yes
|
||||
2.2 and above 2.1.1 2001-now PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||
a modified version without making your changes open source. The
|
||||
GPL-compatible licenses make it possible to combine Python with
|
||||
other software that is released under the GPL; the others don't.
|
||||
|
||||
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||
because its license has a choice of law clause. According to
|
||||
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||
is "not incompatible" with the GPL.
|
||||
|
||||
Thanks to the many outside volunteers who have worked under Guido's
|
||||
direction to make these releases possible.
|
||||
|
||||
|
||||
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||
===============================================================
|
||||
|
||||
Python software and documentation are licensed under the
|
||||
Python Software Foundation License Version 2.
|
||||
|
||||
Starting with Python 3.8.6, examples, recipes, and other code in
|
||||
the documentation are dual licensed under the PSF License Version 2
|
||||
and the Zero-Clause BSD license.
|
||||
|
||||
Some software incorporated into Python is under different licenses.
|
||||
The licenses are listed with code falling under that license.
|
||||
|
||||
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation;
|
||||
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||
prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||
-------------------------------------------
|
||||
|
||||
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||
|
||||
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||
Individual or Organization ("Licensee") accessing and otherwise using
|
||||
this software in source or binary form and its associated
|
||||
documentation ("the Software").
|
||||
|
||||
2. Subject to the terms and conditions of this BeOpen Python License
|
||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||
and/or display publicly, prepare derivative works, distribute, and
|
||||
otherwise use the Software alone or in any derivative version,
|
||||
provided, however, that the BeOpen Python License is retained in the
|
||||
Software, alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
5. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
6. This License Agreement shall be governed by and interpreted in all
|
||||
respects by the law of the State of California, excluding conflict of
|
||||
law provisions. Nothing in this License Agreement shall be deemed to
|
||||
create any relationship of agency, partnership, or joint venture
|
||||
between BeOpen and Licensee. This License Agreement does not grant
|
||||
permission to use BeOpen trademarks or trade names in a trademark
|
||||
sense to endorse or promote products or services of Licensee, or any
|
||||
third party. As an exception, the "BeOpen Python" logos available at
|
||||
http://www.pythonlabs.com/logos.html may be used according to the
|
||||
permissions granted on that web page.
|
||||
|
||||
7. By copying, installing or otherwise using the software, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||
---------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||
source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||
license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||
alone or in any derivative version, provided, however, that CNRI's
|
||||
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||
Agreement, Licensee may substitute the following text (omitting the
|
||||
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||
conditions in CNRI's License Agreement. This Agreement together with
|
||||
Python 1.6.1 may be located on the internet using the following
|
||||
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||
Agreement may also be obtained from a proxy server on the internet
|
||||
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python 1.6.1.
|
||||
|
||||
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. This License Agreement shall be governed by the federal
|
||||
intellectual property law of the United States, including without
|
||||
limitation the federal copyright law, and, to the extent such
|
||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||
Virginia, excluding Virginia's conflict of law provisions.
|
||||
Notwithstanding the foregoing, with regard to derivative works based
|
||||
on Python 1.6.1 that incorporate non-separable material that was
|
||||
previously distributed under the GNU General Public License (GPL), the
|
||||
law of the Commonwealth of Virginia shall govern this License
|
||||
Agreement only as to issues arising under or with respect to
|
||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||
License Agreement shall be deemed to create any relationship of
|
||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||
License Agreement does not grant permission to use CNRI trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or
|
||||
services of Licensee, or any third party.
|
||||
|
||||
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
ACCEPT
|
||||
|
||||
|
||||
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||
The Netherlands. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
5
homeassistant/backports/README
Normal file
5
homeassistant/backports/README
Normal file
@@ -0,0 +1,5 @@
|
||||
This package contains backports of Python functionality from future Python
|
||||
versions.
|
||||
|
||||
Some of the backports have been copied directly from the CPython project,
|
||||
and are subject to license agreement as detailed in LICENSE.Python.
|
||||
@@ -1,4 +1,14 @@
|
||||
"""Functools backports from standard lib."""
|
||||
|
||||
# This file contains parts of Python's module wrapper
|
||||
# for the _functools C module
|
||||
# to allow utilities written in Python to be added
|
||||
# to the functools module.
|
||||
# Written by Nick Coghlan <ncoghlan at gmail.com>,
|
||||
# Raymond Hettinger <python at rcn.com>,
|
||||
# and Łukasz Langa <lukasz at langa.pl>.
|
||||
# Copyright © 2001-2023 Python Software Foundation; All Rights Reserved
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
@@ -68,4 +78,4 @@ class cached_property(Generic[_T]):
|
||||
raise TypeError(msg) from None
|
||||
return val
|
||||
|
||||
__class_getitem__ = classmethod(GenericAlias)
|
||||
__class_getitem__ = classmethod(GenericAlias) # type: ignore[var-annotated]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Support for the Abode Security System."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from functools import partial
|
||||
|
||||
from jaraco.abode.automation import Automation as AbodeAuto
|
||||
@@ -25,7 +26,7 @@ from homeassistant.const import (
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, ServiceCall
|
||||
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, ServiceCall
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv, entity
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
@@ -71,15 +72,14 @@ PLATFORMS = [
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class AbodeSystem:
|
||||
"""Abode System class."""
|
||||
|
||||
def __init__(self, abode: Abode, polling: bool) -> None:
|
||||
"""Initialize the system."""
|
||||
self.abode = abode
|
||||
self.polling = polling
|
||||
self.entity_ids: set[str | None] = set()
|
||||
self.logout_listener = None
|
||||
abode: Abode
|
||||
polling: bool
|
||||
entity_ids: set[str | None] = field(default_factory=set)
|
||||
logout_listener: CALLBACK_TYPE | None = None
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
@@ -127,7 +127,7 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
"""Return the current target temperature."""
|
||||
# If the system is in MyZone mode, and a zone is set, return that temperature instead.
|
||||
if (
|
||||
self._ac["myZone"] > 0
|
||||
self._myzone
|
||||
and not self._ac.get(ADVANTAGE_AIR_MYAUTO_ENABLED)
|
||||
and not self._ac.get(ADVANTAGE_AIR_MYTEMP_ENABLED)
|
||||
):
|
||||
|
||||
@@ -63,7 +63,7 @@ class AdvantageAirAcEntity(AdvantageAirEntity):
|
||||
return self.coordinator.data["aircons"][self.ac_key]["info"]
|
||||
|
||||
@property
|
||||
def _myzone(self) -> dict[str, Any]:
|
||||
def _myzone(self) -> dict[str, Any] | None:
|
||||
return self.coordinator.data["aircons"][self.ac_key]["zones"].get(
|
||||
f"z{self._ac['myZone']:02}"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""The AEMET OpenData component."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aemet_opendata.exceptions import TownNotFound
|
||||
@@ -8,6 +9,7 @@ from aemet_opendata.interface import AEMET, ConnectionOptions
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
|
||||
from .const import (
|
||||
@@ -37,6 +39,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
except TownNotFound as err:
|
||||
_LOGGER.error(err)
|
||||
return False
|
||||
except asyncio.TimeoutError as err:
|
||||
raise ConfigEntryNotReady("AEMET OpenData API timed out") from err
|
||||
|
||||
weather_coordinator = WeatherUpdateCoordinator(hass, aemet)
|
||||
await weather_coordinator.async_config_entry_first_refresh()
|
||||
|
||||
@@ -9,8 +9,9 @@ ATTR_API_CAT_DESCRIPTION = "Name"
|
||||
ATTR_API_O3 = "O3"
|
||||
ATTR_API_PM25 = "PM2.5"
|
||||
ATTR_API_POLLUTANT = "Pollutant"
|
||||
ATTR_API_REPORT_DATE = "HourObserved"
|
||||
ATTR_API_REPORT_HOUR = "DateObserved"
|
||||
ATTR_API_REPORT_DATE = "DateObserved"
|
||||
ATTR_API_REPORT_HOUR = "HourObserved"
|
||||
ATTR_API_REPORT_TZ = "LocalTimeZone"
|
||||
ATTR_API_STATE = "StateCode"
|
||||
ATTR_API_STATION = "ReportingArea"
|
||||
ATTR_API_STATION_LATITUDE = "Latitude"
|
||||
|
||||
@@ -20,6 +20,7 @@ from .const import (
|
||||
ATTR_API_POLLUTANT,
|
||||
ATTR_API_REPORT_DATE,
|
||||
ATTR_API_REPORT_HOUR,
|
||||
ATTR_API_REPORT_TZ,
|
||||
ATTR_API_STATE,
|
||||
ATTR_API_STATION,
|
||||
ATTR_API_STATION_LATITUDE,
|
||||
@@ -83,6 +84,7 @@ class AirNowDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
# Copy Report Details
|
||||
data[ATTR_API_REPORT_DATE] = obv[ATTR_API_REPORT_DATE]
|
||||
data[ATTR_API_REPORT_HOUR] = obv[ATTR_API_REPORT_HOUR]
|
||||
data[ATTR_API_REPORT_TZ] = obv[ATTR_API_REPORT_TZ]
|
||||
|
||||
# Copy Station Details
|
||||
data[ATTR_API_STATE] = obv[ATTR_API_STATE]
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
@@ -13,6 +14,7 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_TIME,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
)
|
||||
@@ -21,6 +23,7 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.dt import get_time_zone
|
||||
|
||||
from . import AirNowDataUpdateCoordinator
|
||||
from .const import (
|
||||
@@ -29,6 +32,9 @@ from .const import (
|
||||
ATTR_API_AQI_LEVEL,
|
||||
ATTR_API_O3,
|
||||
ATTR_API_PM25,
|
||||
ATTR_API_REPORT_DATE,
|
||||
ATTR_API_REPORT_HOUR,
|
||||
ATTR_API_REPORT_TZ,
|
||||
ATTR_API_STATION,
|
||||
ATTR_API_STATION_LATITUDE,
|
||||
ATTR_API_STATION_LONGITUDE,
|
||||
@@ -78,6 +84,12 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||
extra_state_attributes_fn=lambda data: {
|
||||
ATTR_DESCR: data[ATTR_API_AQI_DESCRIPTION],
|
||||
ATTR_LEVEL: data[ATTR_API_AQI_LEVEL],
|
||||
ATTR_TIME: datetime.strptime(
|
||||
f"{data[ATTR_API_REPORT_DATE]} {data[ATTR_API_REPORT_HOUR]}",
|
||||
"%Y-%m-%d %H",
|
||||
)
|
||||
.replace(tzinfo=get_time_zone(data[ATTR_API_REPORT_TZ]))
|
||||
.isoformat(),
|
||||
},
|
||||
),
|
||||
AirNowEntityDescription(
|
||||
|
||||
@@ -226,6 +226,14 @@ class AirthingsSensor(
|
||||
model=airthings_device.model,
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Check if device and sensor is available in data."""
|
||||
return (
|
||||
super().available
|
||||
and self.entity_description.key in self.coordinator.data.sensors
|
||||
)
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the value reported by the sensor."""
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"user": {
|
||||
"description": "[%key:component::bluetooth::config::step::user::description%]",
|
||||
"data": {
|
||||
"address": "[%key:component::bluetooth::config::step::user::data::address%]"
|
||||
"address": "[%key:common::config_flow::data::device%]"
|
||||
}
|
||||
},
|
||||
"bluetooth_confirm": {
|
||||
|
||||
@@ -421,7 +421,6 @@ class AirVisualEntity(CoordinatorEntity):
|
||||
self._entry = entry
|
||||
self.entity_description = description
|
||||
|
||||
# pylint: disable-next=hass-missing-super-call
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"],
|
||||
"requirements": ["aioairzone==0.6.8"]
|
||||
"requirements": ["aioairzone==0.6.9"]
|
||||
}
|
||||
|
||||
@@ -7,15 +7,21 @@ from aioairzone_cloud.common import OperationAction, OperationMode, TemperatureU
|
||||
from aioairzone_cloud.const import (
|
||||
API_MODE,
|
||||
API_OPTS,
|
||||
API_PARAMS,
|
||||
API_POWER,
|
||||
API_SETPOINT,
|
||||
API_UNITS,
|
||||
API_VALUE,
|
||||
AZD_ACTION,
|
||||
AZD_AIDOOS,
|
||||
AZD_GROUPS,
|
||||
AZD_HUMIDITY,
|
||||
AZD_INSTALLATIONS,
|
||||
AZD_MASTER,
|
||||
AZD_MODE,
|
||||
AZD_MODES,
|
||||
AZD_NUM_DEVICES,
|
||||
AZD_NUM_GROUPS,
|
||||
AZD_POWER,
|
||||
AZD_TEMP,
|
||||
AZD_TEMP_SET,
|
||||
@@ -39,7 +45,13 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import AirzoneUpdateCoordinator
|
||||
from .entity import AirzoneEntity, AirzoneZoneEntity
|
||||
from .entity import (
|
||||
AirzoneAidooEntity,
|
||||
AirzoneEntity,
|
||||
AirzoneGroupEntity,
|
||||
AirzoneInstallationEntity,
|
||||
AirzoneZoneEntity,
|
||||
)
|
||||
|
||||
HVAC_ACTION_LIB_TO_HASS: Final[dict[OperationAction, HVACAction]] = {
|
||||
OperationAction.COOLING: HVACAction.COOLING,
|
||||
@@ -82,6 +94,38 @@ async def async_setup_entry(
|
||||
|
||||
entities: list[AirzoneClimate] = []
|
||||
|
||||
# Aidoos
|
||||
for aidoo_id, aidoo_data in coordinator.data.get(AZD_AIDOOS, {}).items():
|
||||
entities.append(
|
||||
AirzoneAidooClimate(
|
||||
coordinator,
|
||||
aidoo_id,
|
||||
aidoo_data,
|
||||
)
|
||||
)
|
||||
|
||||
# Groups
|
||||
for group_id, group_data in coordinator.data.get(AZD_GROUPS, {}).items():
|
||||
if group_data[AZD_NUM_DEVICES] > 1:
|
||||
entities.append(
|
||||
AirzoneGroupClimate(
|
||||
coordinator,
|
||||
group_id,
|
||||
group_data,
|
||||
)
|
||||
)
|
||||
|
||||
# Installations
|
||||
for inst_id, inst_data in coordinator.data.get(AZD_INSTALLATIONS, {}).items():
|
||||
if inst_data[AZD_NUM_GROUPS] > 1:
|
||||
entities.append(
|
||||
AirzoneInstallationClimate(
|
||||
coordinator,
|
||||
inst_id,
|
||||
inst_data,
|
||||
)
|
||||
)
|
||||
|
||||
# Zones
|
||||
for zone_id, zone_data in coordinator.data.get(AZD_ZONES, {}).items():
|
||||
entities.append(
|
||||
@@ -98,9 +142,39 @@ async def async_setup_entry(
|
||||
class AirzoneClimate(AirzoneEntity, ClimateEntity):
|
||||
"""Define an Airzone Cloud climate."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = None
|
||||
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Update attributes when the coordinator updates."""
|
||||
self._async_update_attrs()
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
@callback
|
||||
def _async_update_attrs(self) -> None:
|
||||
"""Update climate attributes."""
|
||||
self._attr_current_temperature = self.get_airzone_value(AZD_TEMP)
|
||||
self._attr_current_humidity = self.get_airzone_value(AZD_HUMIDITY)
|
||||
self._attr_hvac_action = HVAC_ACTION_LIB_TO_HASS[
|
||||
self.get_airzone_value(AZD_ACTION)
|
||||
]
|
||||
if self.get_airzone_value(AZD_POWER):
|
||||
self._attr_hvac_mode = HVAC_MODE_LIB_TO_HASS[
|
||||
self.get_airzone_value(AZD_MODE)
|
||||
]
|
||||
else:
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_max_temp = self.get_airzone_value(AZD_TEMP_SET_MAX)
|
||||
self._attr_min_temp = self.get_airzone_value(AZD_TEMP_SET_MIN)
|
||||
self._attr_target_temperature = self.get_airzone_value(AZD_TEMP_SET)
|
||||
|
||||
|
||||
class AirzoneDeviceClimate(AirzoneClimate):
|
||||
"""Define an Airzone Cloud Device base class."""
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
params = {
|
||||
@@ -131,36 +205,143 @@ class AirzoneClimate(AirzoneEntity, ClimateEntity):
|
||||
}
|
||||
await self._async_update_params(params)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Update attributes when the coordinator updates."""
|
||||
self._async_update_attrs()
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
@callback
|
||||
def _async_update_attrs(self) -> None:
|
||||
"""Update climate attributes."""
|
||||
self._attr_current_temperature = self.get_airzone_value(AZD_TEMP)
|
||||
self._attr_current_humidity = self.get_airzone_value(AZD_HUMIDITY)
|
||||
self._attr_hvac_action = HVAC_ACTION_LIB_TO_HASS[
|
||||
self.get_airzone_value(AZD_ACTION)
|
||||
]
|
||||
if self.get_airzone_value(AZD_POWER):
|
||||
self._attr_hvac_mode = HVAC_MODE_LIB_TO_HASS[
|
||||
self.get_airzone_value(AZD_MODE)
|
||||
]
|
||||
class AirzoneDeviceGroupClimate(AirzoneClimate):
|
||||
"""Define an Airzone Cloud DeviceGroup base class."""
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
params = {
|
||||
API_PARAMS: {
|
||||
API_POWER: True,
|
||||
},
|
||||
}
|
||||
await self._async_update_params(params)
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the entity off."""
|
||||
params = {
|
||||
API_PARAMS: {
|
||||
API_POWER: False,
|
||||
},
|
||||
}
|
||||
await self._async_update_params(params)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
params: dict[str, Any] = {}
|
||||
if ATTR_TEMPERATURE in kwargs:
|
||||
params[API_PARAMS] = {
|
||||
API_SETPOINT: kwargs[ATTR_TEMPERATURE],
|
||||
}
|
||||
params[API_OPTS] = {
|
||||
API_UNITS: TemperatureUnit.CELSIUS.value,
|
||||
}
|
||||
await self._async_update_params(params)
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set hvac mode."""
|
||||
params: dict[str, Any] = {
|
||||
API_PARAMS: {},
|
||||
}
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
params[API_PARAMS][API_POWER] = False
|
||||
else:
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_max_temp = self.get_airzone_value(AZD_TEMP_SET_MAX)
|
||||
self._attr_min_temp = self.get_airzone_value(AZD_TEMP_SET_MIN)
|
||||
self._attr_target_temperature = self.get_airzone_value(AZD_TEMP_SET)
|
||||
mode = HVAC_MODE_HASS_TO_LIB[hvac_mode]
|
||||
params[API_PARAMS][API_MODE] = mode.value
|
||||
params[API_PARAMS][API_POWER] = True
|
||||
await self._async_update_params(params)
|
||||
|
||||
|
||||
class AirzoneZoneClimate(AirzoneZoneEntity, AirzoneClimate):
|
||||
class AirzoneAidooClimate(AirzoneAidooEntity, AirzoneDeviceClimate):
|
||||
"""Define an Airzone Cloud Aidoo climate."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
aidoo_id: str,
|
||||
aidoo_data: dict,
|
||||
) -> None:
|
||||
"""Initialize Airzone Cloud Aidoo climate."""
|
||||
super().__init__(coordinator, aidoo_id, aidoo_data)
|
||||
|
||||
self._attr_unique_id = aidoo_id
|
||||
self._attr_target_temperature_step = self.get_airzone_value(AZD_TEMP_STEP)
|
||||
self._attr_hvac_modes = [
|
||||
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_airzone_value(AZD_MODES)
|
||||
]
|
||||
if HVACMode.OFF not in self._attr_hvac_modes:
|
||||
self._attr_hvac_modes += [HVACMode.OFF]
|
||||
|
||||
self._async_update_attrs()
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set hvac mode."""
|
||||
params: dict[str, Any] = {}
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
params[API_POWER] = {
|
||||
API_VALUE: False,
|
||||
}
|
||||
else:
|
||||
mode = HVAC_MODE_HASS_TO_LIB[hvac_mode]
|
||||
params[API_MODE] = {
|
||||
API_VALUE: mode.value,
|
||||
}
|
||||
params[API_POWER] = {
|
||||
API_VALUE: True,
|
||||
}
|
||||
await self._async_update_params(params)
|
||||
|
||||
|
||||
class AirzoneGroupClimate(AirzoneGroupEntity, AirzoneDeviceGroupClimate):
|
||||
"""Define an Airzone Cloud Group climate."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
group_id: str,
|
||||
group_data: dict,
|
||||
) -> None:
|
||||
"""Initialize Airzone Cloud Group climate."""
|
||||
super().__init__(coordinator, group_id, group_data)
|
||||
|
||||
self._attr_unique_id = group_id
|
||||
self._attr_target_temperature_step = self.get_airzone_value(AZD_TEMP_STEP)
|
||||
self._attr_hvac_modes = [
|
||||
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_airzone_value(AZD_MODES)
|
||||
]
|
||||
if HVACMode.OFF not in self._attr_hvac_modes:
|
||||
self._attr_hvac_modes += [HVACMode.OFF]
|
||||
|
||||
self._async_update_attrs()
|
||||
|
||||
|
||||
class AirzoneInstallationClimate(AirzoneInstallationEntity, AirzoneDeviceGroupClimate):
|
||||
"""Define an Airzone Cloud Installation climate."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
inst_id: str,
|
||||
inst_data: dict,
|
||||
) -> None:
|
||||
"""Initialize Airzone Cloud Installation climate."""
|
||||
super().__init__(coordinator, inst_id, inst_data)
|
||||
|
||||
self._attr_unique_id = inst_id
|
||||
self._attr_target_temperature_step = self.get_airzone_value(AZD_TEMP_STEP)
|
||||
self._attr_hvac_modes = [
|
||||
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_airzone_value(AZD_MODES)
|
||||
]
|
||||
if HVACMode.OFF not in self._attr_hvac_modes:
|
||||
self._attr_hvac_modes += [HVACMode.OFF]
|
||||
|
||||
self._async_update_attrs()
|
||||
|
||||
|
||||
class AirzoneZoneClimate(AirzoneZoneEntity, AirzoneDeviceClimate):
|
||||
"""Define an Airzone Cloud Zone climate."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
@@ -191,7 +372,8 @@ class AirzoneZoneClimate(AirzoneZoneEntity, AirzoneClimate):
|
||||
}
|
||||
else:
|
||||
mode = HVAC_MODE_HASS_TO_LIB[hvac_mode]
|
||||
if mode != self.get_airzone_value(AZD_MODE):
|
||||
cur_mode = self.get_airzone_value(AZD_MODE)
|
||||
if hvac_mode != HVAC_MODE_LIB_TO_HASS[cur_mode]:
|
||||
if self.get_airzone_value(AZD_MASTER):
|
||||
params[API_MODE] = {
|
||||
API_VALUE: mode.value,
|
||||
|
||||
@@ -9,6 +9,8 @@ from aioairzone_cloud.const import (
|
||||
AZD_AIDOOS,
|
||||
AZD_AVAILABLE,
|
||||
AZD_FIRMWARE,
|
||||
AZD_GROUPS,
|
||||
AZD_INSTALLATIONS,
|
||||
AZD_NAME,
|
||||
AZD_SYSTEM_ID,
|
||||
AZD_SYSTEMS,
|
||||
@@ -74,6 +76,104 @@ class AirzoneAidooEntity(AirzoneEntity):
|
||||
value = aidoo.get(key)
|
||||
return value
|
||||
|
||||
async def _async_update_params(self, params: dict[str, Any]) -> None:
|
||||
"""Send Aidoo parameters to Cloud API."""
|
||||
_LOGGER.debug("aidoo=%s: update_params=%s", self.name, params)
|
||||
try:
|
||||
await self.coordinator.airzone.api_set_aidoo_id_params(
|
||||
self.aidoo_id, params
|
||||
)
|
||||
except AirzoneCloudError as error:
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set {self.name} params: {error}"
|
||||
) from error
|
||||
|
||||
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
|
||||
|
||||
|
||||
class AirzoneGroupEntity(AirzoneEntity):
|
||||
"""Define an Airzone Cloud Group entity."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
group_id: str,
|
||||
group_data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
self.group_id = group_id
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, group_id)},
|
||||
manufacturer=MANUFACTURER,
|
||||
name=group_data[AZD_NAME],
|
||||
)
|
||||
|
||||
def get_airzone_value(self, key: str) -> Any:
|
||||
"""Return Group value by key."""
|
||||
value = None
|
||||
if group := self.coordinator.data[AZD_GROUPS].get(self.group_id):
|
||||
value = group.get(key)
|
||||
return value
|
||||
|
||||
async def _async_update_params(self, params: dict[str, Any]) -> None:
|
||||
"""Send Group parameters to Cloud API."""
|
||||
_LOGGER.debug("group=%s: update_params=%s", self.name, params)
|
||||
try:
|
||||
await self.coordinator.airzone.api_set_group_id_params(
|
||||
self.group_id, params
|
||||
)
|
||||
except AirzoneCloudError as error:
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set {self.name} params: {error}"
|
||||
) from error
|
||||
|
||||
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
|
||||
|
||||
|
||||
class AirzoneInstallationEntity(AirzoneEntity):
|
||||
"""Define an Airzone Cloud Installation entity."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirzoneUpdateCoordinator,
|
||||
inst_id: str,
|
||||
inst_data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
self.inst_id = inst_id
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, inst_id)},
|
||||
manufacturer=MANUFACTURER,
|
||||
name=inst_data[AZD_NAME],
|
||||
)
|
||||
|
||||
def get_airzone_value(self, key: str) -> Any:
|
||||
"""Return Installation value by key."""
|
||||
value = None
|
||||
if inst := self.coordinator.data[AZD_INSTALLATIONS].get(self.inst_id):
|
||||
value = inst.get(key)
|
||||
return value
|
||||
|
||||
async def _async_update_params(self, params: dict[str, Any]) -> None:
|
||||
"""Send Installation parameters to Cloud API."""
|
||||
_LOGGER.debug("installation=%s: update_params=%s", self.name, params)
|
||||
try:
|
||||
await self.coordinator.airzone.api_set_installation_id_params(
|
||||
self.inst_id, params
|
||||
)
|
||||
except AirzoneCloudError as error:
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set {self.name} params: {error}"
|
||||
) from error
|
||||
|
||||
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
|
||||
|
||||
|
||||
class AirzoneSystemEntity(AirzoneEntity):
|
||||
"""Define an Airzone Cloud System entity."""
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone_cloud",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aioairzone_cloud"],
|
||||
"requirements": ["aioairzone-cloud==0.2.3"]
|
||||
"requirements": ["aioairzone-cloud==0.3.0"]
|
||||
}
|
||||
|
||||
@@ -580,8 +580,8 @@ class AlexaBrightnessController(AlexaCapability):
|
||||
"""Read and return a property."""
|
||||
if name != "brightness":
|
||||
raise UnsupportedProperty(name)
|
||||
if "brightness" in self.entity.attributes:
|
||||
return round(self.entity.attributes["brightness"] / 255.0 * 100)
|
||||
if brightness := self.entity.attributes.get("brightness"):
|
||||
return round(brightness / 255.0 * 100)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -683,10 +683,8 @@ class AlexaColorTemperatureController(AlexaCapability):
|
||||
"""Read and return a property."""
|
||||
if name != "colorTemperatureInKelvin":
|
||||
raise UnsupportedProperty(name)
|
||||
if "color_temp" in self.entity.attributes:
|
||||
return color_util.color_temperature_mired_to_kelvin(
|
||||
self.entity.attributes["color_temp"]
|
||||
)
|
||||
if color_temp := self.entity.attributes.get("color_temp"):
|
||||
return color_util.color_temperature_mired_to_kelvin(color_temp)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from homeassistant.components.mjpeg import MjpegCamera, filter_urllib3_logging
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_NAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_USERNAME,
|
||||
HTTP_BASIC_AUTHENTICATION,
|
||||
@@ -39,14 +38,7 @@ class IPWebcamCamera(MjpegCamera):
|
||||
|
||||
def __init__(self, coordinator: AndroidIPCamDataUpdateCoordinator) -> None:
|
||||
"""Initialize the camera."""
|
||||
name = None
|
||||
# keep imported name until YAML is removed
|
||||
if CONF_NAME in coordinator.config_entry.data:
|
||||
name = coordinator.config_entry.data[CONF_NAME]
|
||||
self._attr_has_entity_name = False
|
||||
|
||||
super().__init__(
|
||||
name=name,
|
||||
mjpeg_url=coordinator.cam.mjpeg_url,
|
||||
still_image_url=coordinator.cam.image_url,
|
||||
authentication=HTTP_BASIC_AUTHENTICATION,
|
||||
@@ -56,5 +48,5 @@ class IPWebcamCamera(MjpegCamera):
|
||||
self._attr_unique_id = f"{coordinator.config_entry.entry_id}-camera"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
|
||||
name=name or coordinator.config_entry.data[CONF_HOST],
|
||||
name=coordinator.config_entry.data[CONF_HOST],
|
||||
)
|
||||
|
||||
@@ -19,11 +19,6 @@ class AndroidIPCamBaseEntity(CoordinatorEntity[AndroidIPCamDataUpdateCoordinator
|
||||
) -> None:
|
||||
"""Initialize the base entity."""
|
||||
super().__init__(coordinator)
|
||||
if CONF_NAME in coordinator.config_entry.data:
|
||||
# name is legacy imported from YAML config
|
||||
# this block can be removed when removing import from YAML
|
||||
self._attr_name = f"{coordinator.config_entry.data[CONF_NAME]} {self.entity_description.name}"
|
||||
self._attr_has_entity_name = False
|
||||
self.cam = coordinator.cam
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Support for Apache Kafka."""
|
||||
from datetime import datetime
|
||||
import json
|
||||
import sys
|
||||
|
||||
from aiokafka import AIOKafkaProducer
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
@@ -16,11 +16,16 @@ from homeassistant.const import (
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util import ssl as ssl_util
|
||||
|
||||
if sys.version_info < (3, 12):
|
||||
from aiokafka import AIOKafkaProducer
|
||||
|
||||
|
||||
DOMAIN = "apache_kafka"
|
||||
|
||||
CONF_FILTER = "filter"
|
||||
@@ -49,6 +54,10 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Activate the Apache Kafka integration."""
|
||||
if sys.version_info >= (3, 12):
|
||||
raise HomeAssistantError(
|
||||
"Apache Kafka is not supported on Python 3.12. Please use Python 3.11."
|
||||
)
|
||||
conf = config[DOMAIN]
|
||||
|
||||
kafka = hass.data[DOMAIN] = KafkaManager(
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/apprise",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["apprise"],
|
||||
"requirements": ["apprise==1.5.0"]
|
||||
"requirements": ["apprise==1.6.0"]
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
"connectable": false
|
||||
}
|
||||
],
|
||||
"codeowners": ["@aschmitz"],
|
||||
"codeowners": ["@aschmitz", "@thecode"],
|
||||
"config_flow": true,
|
||||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/aranet",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["aranet4==2.1.3"]
|
||||
"requirements": ["aranet4==2.2.2"]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from aranet4.client import Aranet4Advertisement
|
||||
from bleak.backends.device import BLEDevice
|
||||
@@ -32,6 +33,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity import EntityDescription
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -121,22 +123,22 @@ def sensor_update_to_bluetooth_data_update(
|
||||
adv: Aranet4Advertisement,
|
||||
) -> PassiveBluetoothDataUpdate:
|
||||
"""Convert a sensor update to a Bluetooth data update."""
|
||||
data: dict[PassiveBluetoothEntityKey, Any] = {}
|
||||
names: dict[PassiveBluetoothEntityKey, str | None] = {}
|
||||
descs: dict[PassiveBluetoothEntityKey, EntityDescription] = {}
|
||||
for key, desc in SENSOR_DESCRIPTIONS.items():
|
||||
tag = _device_key_to_bluetooth_entity_key(adv.device, key)
|
||||
val = getattr(adv.readings, key)
|
||||
if val == -1:
|
||||
continue
|
||||
data[tag] = val
|
||||
names[tag] = desc.name
|
||||
descs[tag] = desc
|
||||
return PassiveBluetoothDataUpdate(
|
||||
devices={adv.device.address: _sensor_device_info_to_hass(adv)},
|
||||
entity_descriptions={
|
||||
_device_key_to_bluetooth_entity_key(adv.device, key): desc
|
||||
for key, desc in SENSOR_DESCRIPTIONS.items()
|
||||
},
|
||||
entity_data={
|
||||
_device_key_to_bluetooth_entity_key(adv.device, key): getattr(
|
||||
adv.readings, key, None
|
||||
)
|
||||
for key in SENSOR_DESCRIPTIONS
|
||||
},
|
||||
entity_names={
|
||||
_device_key_to_bluetooth_entity_key(adv.device, key): desc.name
|
||||
for key, desc in SENSOR_DESCRIPTIONS.items()
|
||||
},
|
||||
entity_descriptions=descs,
|
||||
entity_data=data,
|
||||
entity_names=names,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"user": {
|
||||
"description": "[%key:component::bluetooth::config::step::user::description%]",
|
||||
"data": {
|
||||
"address": "[%key:component::bluetooth::config::step::user::data::address%]"
|
||||
"address": "[%key:common::config_flow::data::device%]"
|
||||
}
|
||||
},
|
||||
"bluetooth_confirm": {
|
||||
|
||||
@@ -60,7 +60,6 @@ class VariableSensorEntity(AsekoEntity, SensorEntity):
|
||||
|
||||
self._attr_icon = {
|
||||
"clf": "mdi:flask",
|
||||
"ph": "mdi:ph",
|
||||
"rx": "mdi:test-tube",
|
||||
"waterLevel": "mdi:waves",
|
||||
"waterTemp": "mdi:coolant-temperature",
|
||||
@@ -69,6 +68,7 @@ class VariableSensorEntity(AsekoEntity, SensorEntity):
|
||||
self._attr_device_class = {
|
||||
"airTemp": SensorDeviceClass.TEMPERATURE,
|
||||
"waterTemp": SensorDeviceClass.TEMPERATURE,
|
||||
"ph": SensorDeviceClass.PH,
|
||||
}.get(self._variable.type)
|
||||
|
||||
@property
|
||||
|
||||
@@ -58,7 +58,6 @@ class AsusWrtDevice(ScannerEntity):
|
||||
"""Initialize a AsusWrt device."""
|
||||
self._router = router
|
||||
self._device = device
|
||||
self._attr_unique_id = device.mac
|
||||
self._attr_name = device.name or DEFAULT_DEVICE_NAME
|
||||
|
||||
@property
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/august",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pubnub", "yalexs"],
|
||||
"requirements": ["yalexs==1.10.0", "yalexs-ble==2.3.0"]
|
||||
"requirements": ["yalexs==1.10.0", "yalexs-ble==2.3.1"]
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ from yalexs.keypad import KeypadDetail
|
||||
from yalexs.lock import Lock, LockDetail
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
RestoreSensor,
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
@@ -27,7 +28,6 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from . import AugustData
|
||||
from .const import (
|
||||
@@ -174,8 +174,7 @@ async def _async_migrate_old_unique_ids(hass, devices):
|
||||
registry.async_update_entity(old_entity_id, new_unique_id=device.unique_id)
|
||||
|
||||
|
||||
# pylint: disable-next=hass-invalid-inheritance # needs fixing
|
||||
class AugustOperatorSensor(AugustEntityMixin, RestoreEntity, SensorEntity):
|
||||
class AugustOperatorSensor(AugustEntityMixin, RestoreSensor):
|
||||
"""Representation of an August lock operation sensor."""
|
||||
|
||||
_attr_translation_key = "operator"
|
||||
@@ -247,10 +246,15 @@ class AugustOperatorSensor(AugustEntityMixin, RestoreEntity, SensorEntity):
|
||||
await super().async_added_to_hass()
|
||||
|
||||
last_state = await self.async_get_last_state()
|
||||
if not last_state or last_state.state == STATE_UNAVAILABLE:
|
||||
last_sensor_state = await self.async_get_last_sensor_data()
|
||||
if (
|
||||
not last_state
|
||||
or not last_sensor_state
|
||||
or last_state.state == STATE_UNAVAILABLE
|
||||
):
|
||||
return
|
||||
|
||||
self._attr_native_value = last_state.state
|
||||
self._attr_native_value = last_sensor_state.native_value
|
||||
if ATTR_ENTITY_PICTURE in last_state.attributes:
|
||||
self._attr_entity_picture = last_state.attributes[ATTR_ENTITY_PICTURE]
|
||||
if ATTR_OPERATION_REMOTE in last_state.attributes:
|
||||
|
||||
@@ -733,14 +733,14 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity):
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
def _log_callback(self, level: int, msg: str, **kwargs: Any) -> None:
|
||||
"""Log helper callback."""
|
||||
self._logger.log(level, "%s %s", msg, self.name, **kwargs)
|
||||
|
||||
async def _async_attach_triggers(
|
||||
self, home_assistant_start: bool
|
||||
) -> Callable[[], None] | None:
|
||||
"""Set up the triggers."""
|
||||
|
||||
def log_cb(level: int, msg: str, **kwargs: Any) -> None:
|
||||
self._logger.log(level, "%s %s", msg, self.name, **kwargs)
|
||||
|
||||
this = None
|
||||
self.async_write_ha_state()
|
||||
if state := self.hass.states.get(self.entity_id):
|
||||
@@ -763,7 +763,7 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity):
|
||||
self.async_trigger,
|
||||
DOMAIN,
|
||||
str(self.name),
|
||||
log_cb,
|
||||
self._log_callback,
|
||||
home_assistant_start,
|
||||
variables,
|
||||
)
|
||||
|
||||
@@ -42,7 +42,8 @@ class AxisEntity(Entity):
|
||||
self.device = device
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(AXIS_DOMAIN, device.unique_id)}
|
||||
identifiers={(AXIS_DOMAIN, device.unique_id)},
|
||||
serial_number=device.unique_id,
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
|
||||
@@ -247,8 +247,8 @@
|
||||
"presence": {
|
||||
"name": "Presence",
|
||||
"state": {
|
||||
"off": "[%key:component::device_tracker::entity_component::_::state::not_home%]",
|
||||
"on": "[%key:component::device_tracker::entity_component::_::state::home%]"
|
||||
"off": "[%key:common::state::not_home%]",
|
||||
"on": "[%key:common::state::home%]"
|
||||
}
|
||||
},
|
||||
"problem": {
|
||||
|
||||
@@ -8,14 +8,20 @@ from blebox_uniapi.feature import Feature
|
||||
from blebox_uniapi.session import ApiHost
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_USERNAME,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DEFAULT_SETUP_TIMEOUT, DOMAIN, PRODUCT
|
||||
from .helpers import get_maybe_authenticated_session
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -36,12 +42,16 @@ _FeatureT = TypeVar("_FeatureT", bound=Feature)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up BleBox devices from a config entry."""
|
||||
websession = async_get_clientsession(hass)
|
||||
|
||||
host = entry.data[CONF_HOST]
|
||||
port = entry.data[CONF_PORT]
|
||||
|
||||
username = entry.data.get(CONF_USERNAME)
|
||||
password = entry.data.get(CONF_PASSWORD)
|
||||
|
||||
timeout = DEFAULT_SETUP_TIMEOUT
|
||||
|
||||
websession = get_maybe_authenticated_session(hass, password, username)
|
||||
|
||||
api_host = ApiHost(host, port, timeout, websession, hass.loop)
|
||||
|
||||
try:
|
||||
|
||||
@@ -5,16 +5,22 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from blebox_uniapi.box import Box
|
||||
from blebox_uniapi.error import Error, UnsupportedBoxResponse, UnsupportedBoxVersion
|
||||
from blebox_uniapi.error import (
|
||||
Error,
|
||||
UnauthorizedRequest,
|
||||
UnsupportedBoxResponse,
|
||||
UnsupportedBoxVersion,
|
||||
)
|
||||
from blebox_uniapi.session import ApiHost
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import zeroconf
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from . import get_maybe_authenticated_session
|
||||
from .const import (
|
||||
ADDRESS_ALREADY_CONFIGURED,
|
||||
CANNOT_CONNECT,
|
||||
@@ -46,6 +52,8 @@ def create_schema(previous_input=None):
|
||||
{
|
||||
vol.Required(CONF_HOST, default=host): str,
|
||||
vol.Required(CONF_PORT, default=port): int,
|
||||
vol.Inclusive(CONF_USERNAME, "auth"): str,
|
||||
vol.Inclusive(CONF_PASSWORD, "auth"): str,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -153,6 +161,9 @@ class BleBoxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
addr = host_port(user_input)
|
||||
|
||||
username = user_input.get(CONF_USERNAME)
|
||||
password = user_input.get(CONF_PASSWORD)
|
||||
|
||||
for entry in self._async_current_entries():
|
||||
if addr == host_port(entry.data):
|
||||
host, port = addr
|
||||
@@ -160,7 +171,9 @@ class BleBoxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
reason=ADDRESS_ALREADY_CONFIGURED,
|
||||
description_placeholders={"address": f"{host}:{port}"},
|
||||
)
|
||||
websession = async_get_clientsession(hass)
|
||||
|
||||
websession = get_maybe_authenticated_session(hass, password, username)
|
||||
|
||||
api_host = ApiHost(*addr, DEFAULT_SETUP_TIMEOUT, websession, hass.loop, _LOGGER)
|
||||
try:
|
||||
product = await Box.async_from_host(api_host)
|
||||
@@ -169,6 +182,10 @@ class BleBoxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return self.handle_step_exception(
|
||||
"user", ex, schema, *addr, UNSUPPORTED_VERSION, _LOGGER.debug
|
||||
)
|
||||
except UnauthorizedRequest as ex:
|
||||
return self.handle_step_exception(
|
||||
"user", ex, schema, *addr, CANNOT_CONNECT, _LOGGER.error
|
||||
)
|
||||
|
||||
except Error as ex:
|
||||
return self.handle_step_exception(
|
||||
|
||||
21
homeassistant/components/blebox/helpers.py
Normal file
21
homeassistant/components/blebox/helpers.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""Blebox helpers."""
|
||||
from __future__ import annotations
|
||||
|
||||
import aiohttp
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import (
|
||||
async_create_clientsession,
|
||||
async_get_clientsession,
|
||||
)
|
||||
|
||||
|
||||
def get_maybe_authenticated_session(
|
||||
hass: HomeAssistant, password: str | None, username: str | None
|
||||
) -> aiohttp.ClientSession:
|
||||
"""Return proper session object."""
|
||||
if username and password:
|
||||
auth = aiohttp.BasicAuth(login=username, password=password)
|
||||
return async_create_clientsession(hass, auth=auth)
|
||||
|
||||
return async_get_clientsession(hass)
|
||||
@@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/blebox",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["blebox_uniapi"],
|
||||
"requirements": ["blebox-uniapi==2.1.4"],
|
||||
"requirements": ["blebox-uniapi==2.2.0"],
|
||||
"zeroconf": ["_bbxsrv._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"""Support for Blink Home Camera System."""
|
||||
import asyncio
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
|
||||
from aiohttp import ClientError
|
||||
from blinkpy.auth import Auth
|
||||
from blinkpy.blinkpy import Blink
|
||||
import voluptuous as vol
|
||||
@@ -16,8 +18,9 @@ from homeassistant.const import (
|
||||
CONF_SCAN_INTERVAL,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import (
|
||||
DEFAULT_SCAN_INTERVAL,
|
||||
@@ -40,23 +43,7 @@ SERVICE_SAVE_RECENT_CLIPS_SCHEMA = vol.Schema(
|
||||
)
|
||||
|
||||
|
||||
def _blink_startup_wrapper(hass: HomeAssistant, entry: ConfigEntry) -> Blink:
|
||||
"""Startup wrapper for blink."""
|
||||
blink = Blink()
|
||||
auth_data = deepcopy(dict(entry.data))
|
||||
blink.auth = Auth(auth_data, no_prompt=True)
|
||||
blink.refresh_rate = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
||||
|
||||
if blink.start():
|
||||
blink.setup_post_verify()
|
||||
elif blink.auth.check_key_required():
|
||||
_LOGGER.debug("Attempting a reauth flow")
|
||||
_reauth_flow_wrapper(hass, auth_data)
|
||||
|
||||
return blink
|
||||
|
||||
|
||||
def _reauth_flow_wrapper(hass, data):
|
||||
async def _reauth_flow_wrapper(hass, data):
|
||||
"""Reauth flow wrapper."""
|
||||
hass.add_job(
|
||||
hass.config_entries.flow.async_init(
|
||||
@@ -79,10 +66,10 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
data = {**entry.data}
|
||||
if entry.version == 1:
|
||||
data.pop("login_response", None)
|
||||
await hass.async_add_executor_job(_reauth_flow_wrapper, hass, data)
|
||||
await _reauth_flow_wrapper(hass, data)
|
||||
return False
|
||||
if entry.version == 2:
|
||||
await hass.async_add_executor_job(_reauth_flow_wrapper, hass, data)
|
||||
await _reauth_flow_wrapper(hass, data)
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -92,19 +79,33 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
_async_import_options_from_data_if_missing(hass, entry)
|
||||
hass.data[DOMAIN][entry.entry_id] = await hass.async_add_executor_job(
|
||||
_blink_startup_wrapper, hass, entry
|
||||
)
|
||||
session = async_get_clientsession(hass)
|
||||
blink = Blink(session=session)
|
||||
auth_data = deepcopy(dict(entry.data))
|
||||
blink.auth = Auth(auth_data, no_prompt=True, session=session)
|
||||
blink.refresh_rate = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
||||
|
||||
if not hass.data[DOMAIN][entry.entry_id].available:
|
||||
try:
|
||||
await blink.start()
|
||||
except (ClientError, asyncio.TimeoutError) as ex:
|
||||
raise ConfigEntryNotReady("Can not connect to host") from ex
|
||||
|
||||
if blink.auth.check_key_required():
|
||||
_LOGGER.debug("Attempting a reauth flow")
|
||||
raise ConfigEntryAuthFailed("Need 2FA for Blink")
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = blink
|
||||
|
||||
if not blink.available:
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
entry.async_on_unload(entry.add_update_listener(update_listener))
|
||||
await blink.refresh(force=True)
|
||||
|
||||
def blink_refresh(event_time=None):
|
||||
async def blink_refresh(event_time=None):
|
||||
"""Call blink to refresh info."""
|
||||
hass.data[DOMAIN][entry.entry_id].refresh(force_cache=True)
|
||||
await hass.data[DOMAIN][entry.entry_id].refresh(force_cache=True)
|
||||
|
||||
async def async_save_video(call):
|
||||
"""Call save video service handler."""
|
||||
@@ -114,10 +115,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Call save recent clips service handler."""
|
||||
await async_handle_save_recent_clips_service(hass, entry, call)
|
||||
|
||||
def send_pin(call):
|
||||
async def send_pin(call):
|
||||
"""Call blink to send new pin."""
|
||||
pin = call.data[CONF_PIN]
|
||||
hass.data[DOMAIN][entry.entry_id].auth.send_auth_key(
|
||||
await hass.data[DOMAIN][entry.entry_id].auth.send_auth_key(
|
||||
hass.data[DOMAIN][entry.entry_id],
|
||||
pin,
|
||||
)
|
||||
@@ -176,27 +177,27 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
blink.refresh_rate = entry.options[CONF_SCAN_INTERVAL]
|
||||
|
||||
|
||||
async def async_handle_save_video_service(hass, entry, call):
|
||||
async def async_handle_save_video_service(
|
||||
hass: HomeAssistant, entry: ConfigEntry, call
|
||||
) -> None:
|
||||
"""Handle save video service calls."""
|
||||
camera_name = call.data[CONF_NAME]
|
||||
video_path = call.data[CONF_FILENAME]
|
||||
if not hass.config.is_allowed_path(video_path):
|
||||
_LOGGER.error("Can't write %s, no access to path!", video_path)
|
||||
return
|
||||
|
||||
def _write_video(name, file_path):
|
||||
"""Call video write."""
|
||||
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
|
||||
if name in all_cameras:
|
||||
all_cameras[name].video_to_file(file_path)
|
||||
|
||||
try:
|
||||
await hass.async_add_executor_job(_write_video, camera_name, video_path)
|
||||
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
|
||||
if camera_name in all_cameras:
|
||||
await all_cameras[camera_name].video_to_file(video_path)
|
||||
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't write image to file: %s", err)
|
||||
|
||||
|
||||
async def async_handle_save_recent_clips_service(hass, entry, call):
|
||||
async def async_handle_save_recent_clips_service(
|
||||
hass: HomeAssistant, entry: ConfigEntry, call
|
||||
) -> None:
|
||||
"""Save multiple recent clips to output directory."""
|
||||
camera_name = call.data[CONF_NAME]
|
||||
clips_dir = call.data[CONF_FILE_PATH]
|
||||
@@ -204,13 +205,9 @@ async def async_handle_save_recent_clips_service(hass, entry, call):
|
||||
_LOGGER.error("Can't write to directory %s, no access to path!", clips_dir)
|
||||
return
|
||||
|
||||
def _save_recent_clips(name, output_dir):
|
||||
"""Call save recent clips."""
|
||||
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
|
||||
if name in all_cameras:
|
||||
all_cameras[name].save_recent_clips(output_dir=output_dir)
|
||||
|
||||
try:
|
||||
await hass.async_add_executor_job(_save_recent_clips, camera_name, clips_dir)
|
||||
all_cameras = hass.data[DOMAIN][entry.entry_id].cameras
|
||||
if camera_name in all_cameras:
|
||||
await all_cameras[camera_name].save_recent_clips(output_dir=clips_dir)
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't write recent clips to directory: %s", err)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
"""Support for Blink Alarm Control Panel."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from blinkpy.blinkpy import Blink
|
||||
|
||||
from homeassistant.components.alarm_control_panel import (
|
||||
AlarmControlPanelEntity,
|
||||
AlarmControlPanelEntityFeature,
|
||||
@@ -16,6 +19,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DEFAULT_ATTRIBUTION, DEFAULT_BRAND, DOMAIN
|
||||
|
||||
@@ -32,11 +36,11 @@ async def async_setup_entry(
|
||||
|
||||
sync_modules = []
|
||||
for sync_name, sync_module in data.sync.items():
|
||||
sync_modules.append(BlinkSyncModule(data, sync_name, sync_module))
|
||||
async_add_entities(sync_modules)
|
||||
sync_modules.append(BlinkSyncModuleHA(data, sync_name, sync_module))
|
||||
async_add_entities(sync_modules, update_before_add=True)
|
||||
|
||||
|
||||
class BlinkSyncModule(AlarmControlPanelEntity):
|
||||
class BlinkSyncModuleHA(AlarmControlPanelEntity):
|
||||
"""Representation of a Blink Alarm Control Panel."""
|
||||
|
||||
_attr_icon = ICON
|
||||
@@ -44,19 +48,19 @@ class BlinkSyncModule(AlarmControlPanelEntity):
|
||||
_attr_name = None
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, data, name, sync):
|
||||
def __init__(self, data, name: str, sync) -> None:
|
||||
"""Initialize the alarm control panel."""
|
||||
self.data = data
|
||||
self.data: Blink = data
|
||||
self.sync = sync
|
||||
self._name = name
|
||||
self._attr_unique_id = sync.serial
|
||||
self._name: str = name
|
||||
self._attr_unique_id: str = sync.serial
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, sync.serial)},
|
||||
name=f"{DOMAIN} {name}",
|
||||
manufacturer=DEFAULT_BRAND,
|
||||
)
|
||||
|
||||
def update(self) -> None:
|
||||
async def async_update(self) -> None:
|
||||
"""Update the state of the device."""
|
||||
if self.data.check_if_ok_to_update():
|
||||
_LOGGER.debug(
|
||||
@@ -64,23 +68,40 @@ class BlinkSyncModule(AlarmControlPanelEntity):
|
||||
self._name,
|
||||
self.data,
|
||||
)
|
||||
self.data.refresh()
|
||||
try:
|
||||
await self.data.refresh(force=True)
|
||||
self._attr_available = True
|
||||
except asyncio.TimeoutError:
|
||||
self._attr_available = False
|
||||
|
||||
_LOGGER.info("Updating State of Blink Alarm Control Panel '%s'", self._name)
|
||||
|
||||
self._attr_state = (
|
||||
STATE_ALARM_ARMED_AWAY if self.sync.arm else STATE_ALARM_DISARMED
|
||||
)
|
||||
self.sync.attributes["network_info"] = self.data.networks
|
||||
self.sync.attributes["associated_cameras"] = list(self.sync.cameras)
|
||||
self.sync.attributes[ATTR_ATTRIBUTION] = DEFAULT_ATTRIBUTION
|
||||
self._attr_extra_state_attributes = self.sync.attributes
|
||||
|
||||
def alarm_disarm(self, code: str | None = None) -> None:
|
||||
"""Send disarm command."""
|
||||
self.sync.arm = False
|
||||
self.sync.refresh()
|
||||
@property
|
||||
def state(self) -> StateType:
|
||||
"""Return state of alarm."""
|
||||
return STATE_ALARM_ARMED_AWAY if self.sync.arm else STATE_ALARM_DISARMED
|
||||
|
||||
def alarm_arm_away(self, code: str | None = None) -> None:
|
||||
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||
"""Send disarm command."""
|
||||
try:
|
||||
await self.sync.async_arm(False)
|
||||
await self.sync.refresh(force=True)
|
||||
except asyncio.TimeoutError:
|
||||
self._attr_available = False
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||
"""Send arm command."""
|
||||
self.sync.arm = True
|
||||
self.sync.refresh()
|
||||
try:
|
||||
await self.sync.async_arm(True)
|
||||
await self.sync.refresh(force=True)
|
||||
except asyncio.TimeoutError:
|
||||
self._attr_available = False
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -75,15 +75,16 @@ class BlinkBinarySensor(BinarySensorEntity):
|
||||
model=self._camera.camera_type,
|
||||
)
|
||||
|
||||
def update(self) -> None:
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Update sensor state."""
|
||||
state = self._camera.attributes[self.entity_description.key]
|
||||
is_on = self._camera.attributes[self.entity_description.key]
|
||||
_LOGGER.debug(
|
||||
"'%s' %s = %s",
|
||||
self._camera.attributes["name"],
|
||||
self.entity_description.key,
|
||||
state,
|
||||
is_on,
|
||||
)
|
||||
if self.entity_description.key == TYPE_BATTERY:
|
||||
state = state != "ok"
|
||||
self._attr_is_on = state
|
||||
is_on = is_on != "ok"
|
||||
return is_on
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
"""Support for Blink system camera."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Mapping
|
||||
import contextlib
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from requests.exceptions import ChunkedEncodingError
|
||||
|
||||
@@ -41,7 +45,7 @@ class BlinkCamera(Camera):
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = None
|
||||
|
||||
def __init__(self, data, name, camera):
|
||||
def __init__(self, data, name, camera) -> None:
|
||||
"""Initialize a camera."""
|
||||
super().__init__()
|
||||
self.data = data
|
||||
@@ -56,19 +60,25 @@ class BlinkCamera(Camera):
|
||||
_LOGGER.debug("Initialized blink camera %s", self.name)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||
"""Return the camera attributes."""
|
||||
return self._camera.attributes
|
||||
|
||||
def enable_motion_detection(self) -> None:
|
||||
async def async_enable_motion_detection(self) -> None:
|
||||
"""Enable motion detection for the camera."""
|
||||
self._camera.arm = True
|
||||
self.data.refresh()
|
||||
try:
|
||||
await self._camera.async_arm(True)
|
||||
await self.data.refresh(force=True)
|
||||
except asyncio.TimeoutError:
|
||||
self._attr_available = False
|
||||
|
||||
def disable_motion_detection(self) -> None:
|
||||
async def async_disable_motion_detection(self) -> None:
|
||||
"""Disable motion detection for the camera."""
|
||||
self._camera.arm = False
|
||||
self.data.refresh()
|
||||
try:
|
||||
await self._camera.async_arm(False)
|
||||
await self.data.refresh(force=True)
|
||||
except asyncio.TimeoutError:
|
||||
self._attr_available = False
|
||||
|
||||
@property
|
||||
def motion_detection_enabled(self) -> bool:
|
||||
@@ -76,21 +86,22 @@ class BlinkCamera(Camera):
|
||||
return self._camera.arm
|
||||
|
||||
@property
|
||||
def brand(self):
|
||||
def brand(self) -> str | None:
|
||||
"""Return the camera brand."""
|
||||
return DEFAULT_BRAND
|
||||
|
||||
def trigger_camera(self):
|
||||
async def trigger_camera(self) -> None:
|
||||
"""Trigger camera to take a snapshot."""
|
||||
self._camera.snap_picture()
|
||||
self.data.refresh()
|
||||
with contextlib.suppress(asyncio.TimeoutError):
|
||||
await self._camera.snap_picture()
|
||||
self.async_write_ha_state()
|
||||
|
||||
def camera_image(
|
||||
self, width: int | None = None, height: int | None = None
|
||||
) -> bytes | None:
|
||||
"""Return a still image response from the camera."""
|
||||
try:
|
||||
return self._camera.image_from_cache.content
|
||||
return self._camera.image_from_cache
|
||||
except ChunkedEncodingError:
|
||||
_LOGGER.debug("Could not retrieve image for %s", self._camera.name)
|
||||
return None
|
||||
|
||||
@@ -16,10 +16,11 @@ from homeassistant.const import (
|
||||
CONF_SCAN_INTERVAL,
|
||||
CONF_USERNAME,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import selector
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaFlowFormStep,
|
||||
SchemaOptionsFlowHandler,
|
||||
@@ -49,23 +50,23 @@ OPTIONS_FLOW = {
|
||||
}
|
||||
|
||||
|
||||
def validate_input(auth: Auth) -> None:
|
||||
async def validate_input(auth: Auth) -> None:
|
||||
"""Validate the user input allows us to connect."""
|
||||
try:
|
||||
auth.startup()
|
||||
await auth.startup()
|
||||
except (LoginError, TokenRefreshFailed) as err:
|
||||
raise InvalidAuth from err
|
||||
if auth.check_key_required():
|
||||
raise Require2FA
|
||||
|
||||
|
||||
def _send_blink_2fa_pin(auth: Auth, pin: str | None) -> bool:
|
||||
async def _send_blink_2fa_pin(hass: HomeAssistant, auth: Auth, pin: str | None) -> bool:
|
||||
"""Send 2FA pin to blink servers."""
|
||||
blink = Blink()
|
||||
blink = Blink(session=async_get_clientsession(hass))
|
||||
blink.auth = auth
|
||||
blink.setup_login_ids()
|
||||
blink.setup_urls()
|
||||
return auth.send_auth_key(blink, pin)
|
||||
return await auth.send_auth_key(blink, pin)
|
||||
|
||||
|
||||
class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
@@ -91,11 +92,15 @@ class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initiated by the user."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
self.auth = Auth({**user_input, "device_id": DEVICE_ID}, no_prompt=True)
|
||||
self.auth = Auth(
|
||||
{**user_input, "device_id": DEVICE_ID},
|
||||
no_prompt=True,
|
||||
session=async_get_clientsession(self.hass),
|
||||
)
|
||||
await self.async_set_unique_id(user_input[CONF_USERNAME])
|
||||
|
||||
try:
|
||||
await self.hass.async_add_executor_job(validate_input, self.auth)
|
||||
await validate_input(self.auth)
|
||||
return self._async_finish_flow()
|
||||
except Require2FA:
|
||||
return await self.async_step_2fa()
|
||||
@@ -122,11 +127,9 @@ class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle 2FA step."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
pin: str | None = user_input.get(CONF_PIN)
|
||||
try:
|
||||
assert self.auth
|
||||
valid_token = await self.hass.async_add_executor_job(
|
||||
_send_blink_2fa_pin, self.auth, pin
|
||||
valid_token = await _send_blink_2fa_pin(
|
||||
self.hass, self.auth, user_input.get(CONF_PIN)
|
||||
)
|
||||
except BlinkSetupError:
|
||||
errors["base"] = "cannot_connect"
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/blink",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["blinkpy"],
|
||||
"requirements": ["blinkpy==0.21.0"]
|
||||
"requirements": ["blinkpy==0.22.2"]
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
"""Support for Blink system camera sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
@@ -17,6 +20,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DEFAULT_BRAND, DOMAIN, TYPE_TEMPERATURE, TYPE_WIFI_STRENGTH
|
||||
|
||||
@@ -28,6 +32,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_WIFI_STRENGTH,
|
||||
@@ -35,6 +40,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -76,10 +82,11 @@ class BlinkSensor(SensorEntity):
|
||||
model=self._camera.camera_type,
|
||||
)
|
||||
|
||||
def update(self) -> None:
|
||||
@property
|
||||
def native_value(self) -> StateType | date | datetime | Decimal:
|
||||
"""Retrieve sensor data from the camera."""
|
||||
try:
|
||||
self._attr_native_value = self._camera.attributes[self._sensor_key]
|
||||
native_value = self._camera.attributes[self._sensor_key]
|
||||
_LOGGER.debug(
|
||||
"'%s' %s = %s",
|
||||
self._camera.attributes["name"],
|
||||
@@ -87,7 +94,8 @@ class BlinkSensor(SensorEntity):
|
||||
self._attr_native_value,
|
||||
)
|
||||
except KeyError:
|
||||
self._attr_native_value = None
|
||||
native_value = None
|
||||
_LOGGER.error(
|
||||
"%s not a valid camera attribute. Did the API change?", self._sensor_key
|
||||
)
|
||||
return native_value
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"user": {
|
||||
"description": "[%key:component::bluetooth::config::step::user::description%]",
|
||||
"data": {
|
||||
"address": "[%key:component::bluetooth::config::step::user::data::address%]"
|
||||
"address": "[%key:common::config_flow::data::device%]"
|
||||
}
|
||||
},
|
||||
"bluetooth_confirm": {
|
||||
|
||||
@@ -18,11 +18,12 @@ TRACKER_BUFFERING_WOBBLE_SECONDS = 5
|
||||
class AdvertisementTracker:
|
||||
"""Tracker to determine the interval that a device is advertising."""
|
||||
|
||||
__slots__ = ("intervals", "sources", "_timings")
|
||||
__slots__ = ("intervals", "fallback_intervals", "sources", "_timings")
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the tracker."""
|
||||
self.intervals: dict[str, float] = {}
|
||||
self.fallback_intervals: dict[str, float] = {}
|
||||
self.sources: dict[str, str] = {}
|
||||
self._timings: dict[str, list[float]] = {}
|
||||
|
||||
@@ -31,6 +32,7 @@ class AdvertisementTracker:
|
||||
"""Return diagnostics."""
|
||||
return {
|
||||
"intervals": self.intervals,
|
||||
"fallback_intervals": self.fallback_intervals,
|
||||
"sources": self.sources,
|
||||
"timings": self._timings,
|
||||
}
|
||||
@@ -67,6 +69,11 @@ class AdvertisementTracker:
|
||||
self.sources.pop(address, None)
|
||||
self._timings.pop(address, None)
|
||||
|
||||
@callback
|
||||
def async_remove_fallback_interval(self, address: str) -> None:
|
||||
"""Remove fallback interval."""
|
||||
self.fallback_intervals.pop(address, None)
|
||||
|
||||
@callback
|
||||
def async_remove_source(self, source: str) -> None:
|
||||
"""Remove the tracker."""
|
||||
|
||||
@@ -109,6 +109,7 @@ class BluetoothManager:
|
||||
"_cancel_logging_listener",
|
||||
"_advertisement_tracker",
|
||||
"_fallback_intervals",
|
||||
"_intervals",
|
||||
"_unavailable_callbacks",
|
||||
"_connectable_unavailable_callbacks",
|
||||
"_callback_index",
|
||||
@@ -140,7 +141,8 @@ class BluetoothManager:
|
||||
self._cancel_logging_listener: CALLBACK_TYPE | None = None
|
||||
|
||||
self._advertisement_tracker = AdvertisementTracker()
|
||||
self._fallback_intervals: dict[str, float] = {}
|
||||
self._fallback_intervals = self._advertisement_tracker.fallback_intervals
|
||||
self._intervals = self._advertisement_tracker.intervals
|
||||
|
||||
self._unavailable_callbacks: dict[
|
||||
str, list[Callable[[BluetoothServiceInfoBleak], None]]
|
||||
@@ -359,7 +361,7 @@ class BluetoothManager:
|
||||
# The second loop (connectable=False) is responsible for removing
|
||||
# the device from all the interval tracking since it is no longer
|
||||
# available for both connectable and non-connectable
|
||||
self._fallback_intervals.pop(address, None)
|
||||
tracker.async_remove_fallback_interval(address)
|
||||
tracker.async_remove_address(address)
|
||||
self._integration_matcher.async_clear_address(address)
|
||||
self._async_dismiss_discoveries(address)
|
||||
@@ -390,7 +392,7 @@ class BluetoothManager:
|
||||
) -> bool:
|
||||
"""Prefer previous advertisement from a different source if it is better."""
|
||||
if new.time - old.time > (
|
||||
stale_seconds := self._advertisement_tracker.intervals.get(
|
||||
stale_seconds := self._intervals.get(
|
||||
new.address,
|
||||
self._fallback_intervals.get(
|
||||
new.address, FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS
|
||||
@@ -791,7 +793,7 @@ class BluetoothManager:
|
||||
@hass_callback
|
||||
def async_get_learned_advertising_interval(self, address: str) -> float | None:
|
||||
"""Get the learned advertising interval for a MAC address."""
|
||||
return self._advertisement_tracker.intervals.get(address)
|
||||
return self._intervals.get(address)
|
||||
|
||||
@hass_callback
|
||||
def async_get_fallback_availability_interval(self, address: str) -> float | None:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"bleak-retry-connector==3.2.1",
|
||||
"bluetooth-adapters==0.16.1",
|
||||
"bluetooth-auto-recovery==1.2.3",
|
||||
"bluetooth-data-tools==1.12.0",
|
||||
"dbus-fast==2.11.1"
|
||||
"bluetooth-data-tools==1.13.0",
|
||||
"dbus-fast==2.12.0"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
from homeassistant.helpers.entity_platform import async_get_current_platform
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.storage import Store
|
||||
from homeassistant.helpers.typing import UNDEFINED
|
||||
from homeassistant.util.enum import try_parse_enum
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -119,7 +120,7 @@ def serialize_entity_description(description: EntityDescription) -> dict[str, An
|
||||
}
|
||||
|
||||
|
||||
@dataclasses.dataclass(slots=True, frozen=True)
|
||||
@dataclasses.dataclass(slots=True, frozen=False)
|
||||
class PassiveBluetoothDataUpdate(Generic[_T]):
|
||||
"""Generic bluetooth data."""
|
||||
|
||||
@@ -134,12 +135,33 @@ class PassiveBluetoothDataUpdate(Generic[_T]):
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
def update(self, new_data: PassiveBluetoothDataUpdate[_T]) -> None:
|
||||
"""Update the data."""
|
||||
self.devices.update(new_data.devices)
|
||||
self.entity_descriptions.update(new_data.entity_descriptions)
|
||||
self.entity_data.update(new_data.entity_data)
|
||||
self.entity_names.update(new_data.entity_names)
|
||||
def update(
|
||||
self, new_data: PassiveBluetoothDataUpdate[_T]
|
||||
) -> set[PassiveBluetoothEntityKey] | None:
|
||||
"""Update the data and returned changed PassiveBluetoothEntityKey or None on device change.
|
||||
|
||||
The changed PassiveBluetoothEntityKey can be used to filter
|
||||
which listeners are called.
|
||||
"""
|
||||
device_change = False
|
||||
changed_entity_keys: set[PassiveBluetoothEntityKey] = set()
|
||||
for key, device_info in new_data.devices.items():
|
||||
if device_change or self.devices.get(key, UNDEFINED) != device_info:
|
||||
device_change = True
|
||||
self.devices[key] = device_info
|
||||
for incoming, current in (
|
||||
(new_data.entity_descriptions, self.entity_descriptions),
|
||||
(new_data.entity_names, self.entity_names),
|
||||
(new_data.entity_data, self.entity_data),
|
||||
):
|
||||
# mypy can't seem to work this out
|
||||
for key, data in incoming.items(): # type: ignore[attr-defined]
|
||||
if current.get(key, UNDEFINED) != data: # type: ignore[attr-defined]
|
||||
changed_entity_keys.add(key) # type: ignore[arg-type]
|
||||
current[key] = data # type: ignore[index]
|
||||
# If the device changed we don't need to return the changed
|
||||
# entity keys as all entities will be updated
|
||||
return None if device_change else changed_entity_keys
|
||||
|
||||
def async_get_restore_data(self) -> RestoredPassiveBluetoothDataUpdate:
|
||||
"""Serialize restore data to storage."""
|
||||
@@ -470,7 +492,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
||||
data: PassiveBluetoothDataUpdate[_T] | None,
|
||||
) -> None:
|
||||
"""Listen for new entities."""
|
||||
if data is None:
|
||||
if data is None or created.issuperset(data.entity_descriptions):
|
||||
return
|
||||
entities: list[PassiveBluetoothProcessorEntity] = []
|
||||
for entity_key, description in data.entity_descriptions.items():
|
||||
@@ -520,6 +542,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
||||
self,
|
||||
data: PassiveBluetoothDataUpdate[_T] | None,
|
||||
was_available: bool | None = None,
|
||||
changed_entity_keys: set[PassiveBluetoothEntityKey] | None = None,
|
||||
) -> None:
|
||||
"""Update all registered listeners."""
|
||||
if was_available is None:
|
||||
@@ -542,6 +565,12 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
||||
# if the key is in the data
|
||||
entity_key_listeners = self._entity_key_listeners
|
||||
for entity_key in data.entity_data:
|
||||
if (
|
||||
was_available
|
||||
and changed_entity_keys is not None
|
||||
and entity_key not in changed_entity_keys
|
||||
):
|
||||
continue
|
||||
if maybe_listener := entity_key_listeners.get(entity_key):
|
||||
for update_callback in maybe_listener:
|
||||
update_callback(data)
|
||||
@@ -573,8 +602,8 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
||||
"Processing %s data recovered", self.coordinator.name
|
||||
)
|
||||
|
||||
self.data.update(new_data)
|
||||
self.async_update_listeners(new_data, was_available)
|
||||
changed_entity_keys = self.data.update(new_data)
|
||||
self.async_update_listeners(new_data, was_available, changed_entity_keys)
|
||||
|
||||
|
||||
class PassiveBluetoothProcessorEntity(Entity, Generic[_PassiveBluetoothDataProcessorT]):
|
||||
|
||||
@@ -30,6 +30,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ALLOWED_CONDITION_BASED_SERVICE_KEYS = {
|
||||
"BRAKE_FLUID",
|
||||
"BRAKE_PADS_FRONT",
|
||||
"BRAKE_PADS_REAR",
|
||||
"EMISSION_CHECK",
|
||||
"ENGINE_OIL",
|
||||
"OIL",
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["bimmer_connected"],
|
||||
"requirements": ["bimmer-connected==0.14.1"]
|
||||
"requirements": ["bimmer-connected==0.14.2"]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import Any, cast
|
||||
from aiohttp import ClientResponseError
|
||||
from bond_async import Action, Bond, BondType
|
||||
|
||||
from homeassistant.util.async_ import gather_with_concurrency
|
||||
from homeassistant.util.async_ import gather_with_limited_concurrency
|
||||
|
||||
from .const import BRIDGE_MAKE
|
||||
|
||||
@@ -70,7 +70,7 @@ class BondDevice:
|
||||
@property
|
||||
def trust_state(self) -> bool:
|
||||
"""Check if Trust State is turned on."""
|
||||
return self.props.get("trust_state", False)
|
||||
return self.props.get("trust_state", False) # type: ignore[no-any-return]
|
||||
|
||||
def has_action(self, action: str) -> bool:
|
||||
"""Check to see if the device supports an actions."""
|
||||
@@ -163,7 +163,7 @@ class BondHub:
|
||||
]
|
||||
)
|
||||
|
||||
responses = await gather_with_concurrency(MAX_REQUESTS, *tasks)
|
||||
responses = await gather_with_limited_concurrency(MAX_REQUESTS, *tasks)
|
||||
response_idx = 0
|
||||
for device_id in setup_device_ids:
|
||||
self._devices.append(
|
||||
@@ -203,7 +203,7 @@ class BondHub:
|
||||
@property
|
||||
def make(self) -> str:
|
||||
"""Return this hub make."""
|
||||
return self._version.get("make", BRIDGE_MAKE)
|
||||
return self._version.get("make", BRIDGE_MAKE) # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
||||
@@ -4,18 +4,23 @@ from __future__ import annotations
|
||||
from asyncio import timeout
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from brother import Brother, BrotherSensors, SnmpError, UnsupportedModelError
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_TYPE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DATA_CONFIG_ENTRY, DOMAIN, SNMP
|
||||
from .utils import get_snmp_engine
|
||||
|
||||
if sys.version_info < (3, 12):
|
||||
from brother import Brother, BrotherSensors, SnmpError, UnsupportedModelError
|
||||
else:
|
||||
BrotherSensors = Any
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
@@ -25,6 +30,10 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Brother from a config entry."""
|
||||
if sys.version_info >= (3, 12):
|
||||
raise HomeAssistantError(
|
||||
"Brother Printer is not supported on Python 3.12. Please use Python 3.11."
|
||||
)
|
||||
host = entry.data[CONF_HOST]
|
||||
printer_type = entry.data[CONF_TYPE]
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Brother helpers functions."""
|
||||
import logging
|
||||
from __future__ import annotations
|
||||
|
||||
import pysnmp.hlapi.asyncio as hlapi
|
||||
from pysnmp.hlapi.asyncio.cmdgen import lcd
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
@@ -10,6 +10,10 @@ from homeassistant.helpers import singleton
|
||||
|
||||
from .const import DOMAIN, SNMP
|
||||
|
||||
if sys.version_info < (3, 12):
|
||||
import pysnmp.hlapi.asyncio as hlapi
|
||||
from pysnmp.hlapi.asyncio.cmdgen import lcd
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -18,11 +18,10 @@ DATA_SCHEMA = vol.Schema(
|
||||
vol.Optional(CONF_LOCATION): selector.LocationSelector(
|
||||
selector.LocationSelectorConfig(radius=False, icon="")
|
||||
),
|
||||
vol.Optional(CONF_AREA, default="none"): selector.SelectSelector(
|
||||
vol.Optional(CONF_AREA): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=AREAS,
|
||||
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||
translation_key="areas",
|
||||
)
|
||||
),
|
||||
}
|
||||
@@ -34,21 +33,6 @@ class BPKConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_import(self, config: dict[str, Any]) -> FlowResult:
|
||||
"""Import a configuration from config.yaml."""
|
||||
|
||||
if config.get(CONF_LATITUDE):
|
||||
config[CONF_LOCATION] = {
|
||||
CONF_LATITUDE: config[CONF_LATITUDE],
|
||||
CONF_LONGITUDE: config[CONF_LONGITUDE],
|
||||
}
|
||||
if not config.get(CONF_AREA):
|
||||
config[CONF_AREA] = "none"
|
||||
else:
|
||||
config[CONF_AREA] = config[CONF_AREA][0]
|
||||
|
||||
return await self.async_step_user(user_input=config)
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
@@ -58,9 +42,7 @@ class BPKConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
if user_input is not None:
|
||||
latitude: float | None = None
|
||||
longitude: float | None = None
|
||||
area: str | None = (
|
||||
user_input[CONF_AREA] if user_input[CONF_AREA] != "none" else None
|
||||
)
|
||||
area: str | None = user_input.get(CONF_AREA)
|
||||
|
||||
if area:
|
||||
name = f"{DEFAULT_NAME} {area}"
|
||||
|
||||
@@ -14,7 +14,6 @@ CONF_APP_ID = "app_id"
|
||||
DEFAULT_NAME = "Brottsplatskartan"
|
||||
|
||||
AREAS = [
|
||||
"none",
|
||||
"Blekinge län",
|
||||
"Dalarnas län",
|
||||
"Gotlands län",
|
||||
|
||||
@@ -5,66 +5,18 @@ from collections import defaultdict
|
||||
from datetime import timedelta
|
||||
|
||||
from brottsplatskartan import ATTRIBUTION, BrottsplatsKartan
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
|
||||
SensorEntity,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from .const import AREAS, CONF_APP_ID, CONF_AREA, DEFAULT_NAME, DOMAIN, LOGGER
|
||||
from .const import CONF_APP_ID, CONF_AREA, DOMAIN, LOGGER
|
||||
|
||||
SCAN_INTERVAL = timedelta(minutes=30)
|
||||
|
||||
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Inclusive(CONF_LATITUDE, "coordinates"): cv.latitude,
|
||||
vol.Inclusive(CONF_LONGITUDE, "coordinates"): cv.longitude,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_AREA, default=[]): vol.All(cv.ensure_list, [vol.In(AREAS)]),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Brottsplatskartan platform."""
|
||||
|
||||
async_create_issue(
|
||||
hass,
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
f"deprecated_yaml_{DOMAIN}",
|
||||
breaks_in_ha_version="2023.11.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
translation_placeholders={
|
||||
"domain": DOMAIN,
|
||||
"integration_title": "Brottsplatskartan",
|
||||
},
|
||||
)
|
||||
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=config,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user