Compare commits
5012 commits
unifi_comb
...
dev
Author | SHA1 | Date | |
---|---|---|---|
|
1ce8bfdaa4 | ||
|
cd12720085 | ||
|
c7ee7dc880 | ||
|
472414a8d6 | ||
|
0c44c632d4 | ||
|
61d0de3042 | ||
|
01332a542c | ||
|
3d84e35268 | ||
|
eea782bbfe | ||
|
a949d18c30 | ||
|
a748897bd2 | ||
|
3201142fd8 | ||
|
d0a58b68e8 | ||
|
93f79be2f4 | ||
|
46cfe6aa32 | ||
|
301043ec38 | ||
|
245fc246d8 | ||
|
58fd917cb7 | ||
|
2c1d1f5777 | ||
|
938b1eca22 | ||
|
2fda4c82de | ||
|
4200913d03 | ||
|
4aad614497 | ||
|
6a3b4a6a23 | ||
|
51c6ee97b1 | ||
|
4002bc3c25 | ||
|
c35ef6bda3 | ||
|
ed5560aec2 | ||
|
0a5a2de78e | ||
|
7fd337d67f | ||
|
5f68d405b2 | ||
|
093b16c723 | ||
|
ac4cb52dbb | ||
|
72b976f832 | ||
|
f6bc5f050e | ||
|
8300afc00d | ||
|
ab11b84678 | ||
|
b78453b85b | ||
|
b270e4556c | ||
|
e90893e2bc | ||
|
a06e7e31b9 | ||
|
2eaaadd736 | ||
|
0ac00ef092 | ||
|
3092297979 | ||
|
827875473b | ||
|
5cce369ce8 | ||
|
fdb773c921 | ||
|
8b505a2273 | ||
|
a9f468509b | ||
|
4ff8b8015c | ||
|
5c52e865a0 | ||
|
6bfc0cbb0c | ||
|
388473ecd7 | ||
|
285468d85f | ||
|
167025a18c | ||
|
ac0c75a598 | ||
|
cb9cc0f801 | ||
|
7758d8ba48 | ||
|
7045b776b6 | ||
|
22aed92461 | ||
|
60bf0f6b06 | ||
|
3eab72b2aa | ||
|
d1c3e1caa9 | ||
|
8b547551e2 | ||
|
f1ce7ee8ce | ||
|
e388e9f396 | ||
|
96c12fdd10 | ||
|
e97a5f927c | ||
|
313309a7e0 | ||
|
ebe62501d6 | ||
|
c54369fe93 | ||
|
c89bf6a9aa | ||
|
906bdda6fa | ||
|
f3708549f0 | ||
|
3f34ddd74f | ||
|
b19c44b4a5 | ||
|
0cc50bc7bc | ||
|
e56dec2c8e | ||
|
e797149a16 | ||
|
c96f1c87a6 | ||
|
388c5807ea | ||
|
41c6eeedca | ||
|
829632b0af | ||
|
5293fc73d8 | ||
|
870bf388e0 | ||
|
7a4dac1eb1 | ||
|
88480d154a | ||
|
5497c440d9 | ||
|
1e26cf13d6 | ||
|
0dd208a4b9 | ||
|
c3492bc0ed | ||
|
85bf8d1374 | ||
|
e040eb0ff2 | ||
|
d7f41ff8a9 | ||
|
de5437f61e | ||
|
c52a893e21 | ||
|
f7f1830b7e | ||
|
784ad20fb6 | ||
|
0468e7e7a3 | ||
|
88c227681d | ||
|
3a37ff13a6 | ||
|
73929e6791 | ||
|
980b0fa5e6 | ||
|
fbc4a87166 | ||
|
7f9ec2a79e | ||
|
d8b55d39e4 | ||
|
ee41725b53 | ||
|
ae1203336d | ||
|
f10063c9be | ||
|
1da4579a09 | ||
|
7fd9339ad8 | ||
|
de391fa98b | ||
|
70211ab78e | ||
|
a1a08f7755 | ||
|
433321136d | ||
|
0677bba5bd | ||
|
d0ad834d93 | ||
|
7d2d6a82b0 | ||
|
e8dc62411a | ||
|
7925007ab4 | ||
|
7515deddab | ||
|
e382f924e6 | ||
|
7fdcb98518 | ||
|
d0dbca41f7 | ||
|
f3229c723c | ||
|
cafa598fd6 | ||
|
73a62a09b0 | ||
|
ecd8dde347 | ||
|
31a2bb1b98 | ||
|
0fc019305e | ||
|
adb1c59859 | ||
|
5d0277a0d1 | ||
|
21d81d5a5c | ||
|
0de4bfcc2c | ||
|
2cc5486794 | ||
|
e3315383ab | ||
|
31b505828b | ||
|
b61580a937 | ||
|
928e5348e4 | ||
|
622682eb43 | ||
|
97fa568876 | ||
|
c10f078f2a | ||
|
e6d16f06fc | ||
|
c89ab7a142 | ||
|
6837ea947c | ||
|
5f0f29704b | ||
|
1f43dc6676 | ||
|
4d7405de2c | ||
|
4adffdd1a6 | ||
|
4e2f5bdb7d | ||
|
03bc711c51 | ||
|
8b8e949bdf | ||
|
69ba0d3a50 | ||
|
25fb70f281 | ||
|
0304588bb8 | ||
|
08f5081197 | ||
|
701f35488c | ||
|
d11012b2b7 | ||
|
8384100e1b | ||
|
cd0349ee4d | ||
|
b413e481cb | ||
|
9f7e6048f8 | ||
|
2802b77f21 | ||
|
964ad43a27 | ||
|
182be6e0ea | ||
|
cd11f01ace | ||
|
742eca5927 | ||
|
48e7fed901 | ||
|
0a4c0fe7cc | ||
|
9037cb8a7d | ||
|
c97cc34879 | ||
|
1ac9217630 | ||
|
e4036a2f14 | ||
|
da9c73a767 | ||
|
e4aaaf10c3 | ||
|
a7be76ba0a | ||
|
f7cc91903c | ||
|
4a8a674bd3 | ||
|
a8db25fbd8 | ||
|
2dc81ed866 | ||
|
c4762f3ff4 | ||
|
14285973b8 | ||
|
353ccf3ea7 | ||
|
6b90d8ff1a | ||
|
51e691f832 | ||
|
6c7ac7a6ef | ||
|
52ed1bf44a | ||
|
3eab0b704e | ||
|
1f32e02ba2 | ||
|
074418f8f7 | ||
|
b711b17193 | ||
|
03c3d09583 | ||
|
f49547d598 | ||
|
7678be8e2b | ||
|
7672215095 | ||
|
18cf96b92b | ||
|
94d597fd41 | ||
|
24b47b50ea | ||
|
e3dfa84d65 | ||
|
ed1366f463 | ||
|
5d5908a03f | ||
|
3062bad19e | ||
|
28832cbd3e | ||
|
ce94073321 | ||
|
fa61e02207 | ||
|
d1dab83f10 | ||
|
2b7d593ebe | ||
|
e407b4730d | ||
|
0d19e85a0d | ||
|
dac6271e01 | ||
|
8cae8edc55 | ||
|
a3b0909e3f | ||
|
ee30520b57 | ||
|
536e686892 | ||
|
ef767c2b9f | ||
|
c1ecc13cb3 | ||
|
c5e3ba536c | ||
|
0e324c074a | ||
|
a3ba7803db | ||
|
49bf5db5ff | ||
|
50981c26ad | ||
|
2adbf7c933 | ||
|
838ef0bb9f | ||
|
43c2658962 | ||
|
bbefa971d8 | ||
|
cb97f2f13c | ||
|
a657b9bb84 | ||
|
2d2f55a4df | ||
|
df16e6d022 | ||
|
56212c6fa5 | ||
|
bc964ce7f0 | ||
|
ed4f55406c | ||
|
03d5b18974 | ||
|
53c486ccd1 | ||
|
9a2a177b28 | ||
|
18e12740d9 | ||
|
5a24b670a2 | ||
|
94c5c8f42e | ||
|
e84d5fba11 | ||
|
b808c0c5eb | ||
|
782417528c | ||
|
7757423d18 | ||
|
e5a28f4f25 | ||
|
c18d50910f | ||
|
d4adb1f298 | ||
|
fe0a822721 | ||
|
9f427893b1 | ||
|
3b840c684b | ||
|
bc84fdc64a | ||
|
401262c23d | ||
|
795384ca2d | ||
|
dfc3423c83 | ||
|
22b5071c26 | ||
|
4b9524c5c1 | ||
|
9cd46c7f03 | ||
|
232a6868ff | ||
|
361e0d4fc7 | ||
|
26d8d5343a | ||
|
995aab8347 | ||
|
399011552b | ||
|
0c9f30364c | ||
|
bdc17621ee | ||
|
399c53a57e | ||
|
f55e13bde4 | ||
|
dea31e5744 | ||
|
48d9df89ac | ||
|
adf836d9ac | ||
|
51d6948848 | ||
|
7ce74cb5ec | ||
|
29ba140816 | ||
|
0ca4f3e1ba | ||
|
0430e6794e | ||
|
29fa7f827a | ||
|
57d1001603 | ||
|
96de4b3828 | ||
|
c6cb2884f4 | ||
|
27e81fe0ed | ||
|
2c1db10986 | ||
|
a7ba4bd086 | ||
|
25449b424f | ||
|
f6f89bd807 | ||
|
370d7d6bdf | ||
|
4dbf3359c1 | ||
|
25eb7173bf | ||
|
648c3d500b | ||
|
33016c2977 | ||
|
5679b061d2 | ||
|
2eb2bdd615 | ||
|
184cbfea23 | ||
|
f88bc008e5 | ||
|
a927312fb5 | ||
|
5f13db2356 | ||
|
64e84e2aa0 | ||
|
901457e7aa | ||
|
89a9c2ec24 | ||
|
9e04457472 | ||
|
6ecdbb677f | ||
|
211ce43127 | ||
|
f5555df990 | ||
|
82c2422990 | ||
|
734ebc1adb | ||
|
eb3371beef | ||
|
e1ef1063fe | ||
|
c355a53485 | ||
|
79de1d9ed4 | ||
|
7fefa5c235 | ||
|
94db78a0be | ||
|
83a1b06b56 | ||
|
1e42a38473 | ||
|
c54ed53a81 | ||
|
611a952232 | ||
|
05e76105ad | ||
|
ed56e5d631 | ||
|
9253fa4471 | ||
|
c85eb6bf8e | ||
|
cc30d34e87 | ||
|
14875a1101 | ||
|
030aebb97f | ||
|
6e2f36b6d4 | ||
|
25a05eb156 | ||
|
b71c4377f6 | ||
|
d671341864 | ||
|
383f712d43 | ||
|
8a20cd77a0 | ||
|
14023644ef | ||
|
496fc42b94 | ||
|
da0688ce8e | ||
|
89d3707cb7 | ||
|
3f5e395e2f | ||
|
00ea1cab9f | ||
|
5f36062ef3 | ||
|
e562b6f42b | ||
|
b76a94bd42 | ||
|
4e11ff05de | ||
|
080e3d7a42 | ||
|
69e3348cd7 | ||
|
6caa4baa00 | ||
|
4729b19dc6 | ||
|
8abbc4abbc | ||
|
3a667bce8c | ||
|
4c86102daf | ||
|
15bf652f37 | ||
|
eafed2b86c | ||
|
79901cede9 | ||
|
27dc82d7d0 | ||
|
ae37c8cc7a | ||
|
5eadfcc524 | ||
|
5fd1e23255 | ||
|
72bcc6702f | ||
|
8889464e04 | ||
|
af58b0c3b7 | ||
|
e9e20229a3 | ||
|
80ff6dc618 | ||
|
fa30100160 | ||
|
e6c20333b3 | ||
|
3858400a6f | ||
|
95eefbac20 | ||
|
e1e731eb48 | ||
|
f7ce4ff25c | ||
|
c7b2ffbc8e | ||
|
3a1502e2bb | ||
|
b830f83a34 | ||
|
2982e733bc | ||
|
e89ce215c6 | ||
|
b6345f8d07 | ||
|
9d261bab48 | ||
|
b6f875134e | ||
|
90ceebdf91 | ||
|
617e87e02c | ||
|
dafd54ba2b | ||
|
e8c3539709 | ||
|
e5263dc0c8 | ||
|
3584c710b9 | ||
|
0b56ef5699 | ||
|
90bd9bb626 | ||
|
03e6a13896 | ||
|
9fb3261f02 | ||
|
0bc6b8b0d4 | ||
|
18d2ced045 | ||
|
6c75e0bee1 | ||
|
0b981f42bb | ||
|
82868a8588 | ||
|
6e93777f54 | ||
|
9349292464 | ||
|
7084b3b52c | ||
|
0f0f5fd0ab | ||
|
cb0b942db3 | ||
|
b1c9f83952 | ||
|
1ff0efc97b | ||
|
a4da2a9eb5 | ||
|
ba3cfb5f87 | ||
|
bf196935f6 | ||
|
6e98343706 | ||
|
de453ab5c1 | ||
|
f408de4fc3 | ||
|
7863927c3a | ||
|
9fcf757021 | ||
|
fc0547ccdf | ||
|
22f8f117fb | ||
|
2052579efc | ||
|
b8f2583bc3 | ||
|
6323a078e1 | ||
|
ca0be3ec8a | ||
|
91157c21ef | ||
|
cc4fae10f5 | ||
|
d180ff417d | ||
|
8870b657d1 | ||
|
81735b7b47 | ||
|
7fd261347b | ||
|
df796d432e | ||
|
f6e36615d6 | ||
|
0278735dbf | ||
|
9c8d8fef16 | ||
|
6897b24c10 | ||
|
a2a3f59e65 | ||
|
2626a74840 | ||
|
689260f581 | ||
|
f1a2c8be4b | ||
|
0579d565dd | ||
|
f141f5f908 | ||
|
0c25252d9f | ||
|
400b377aa8 | ||
|
a5f3c434e0 | ||
|
365f8046ac | ||
|
4ac35d40cd | ||
|
7691991a93 | ||
|
d0c45b1857 | ||
|
02750452df | ||
|
41a81cbf15 | ||
|
ff621d5bf3 | ||
|
6d561a9796 | ||
|
4784199038 | ||
|
df35c8e707 | ||
|
57eeaf1f75 | ||
|
3cadc1796f | ||
|
ae06f734ce | ||
|
08a53362a7 | ||
|
274c928ec0 | ||
|
d75dda0c05 | ||
|
0c40fcdaeb | ||
|
0a1ba8a4a3 | ||
|
018acc0a3c | ||
|
3a293c6bc4 | ||
|
9155d56190 | ||
|
461dc13da9 | ||
|
b48e2127b8 | ||
|
11ab992dbb | ||
|
4be2cdf90a | ||
|
cdd5cb2876 | ||
|
cdc67aa891 | ||
|
6a22a2b867 | ||
|
0883b23d0c | ||
|
595459bfda | ||
|
5141a4d292 | ||
|
cf8b7607ae | ||
|
b38fe00387 | ||
|
5d446f0e14 | ||
|
a592ece9c8 | ||
|
9cb60c61d1 | ||
|
90ed06c354 | ||
|
22d64cb8f4 | ||
|
453039e860 | ||
|
e727162225 | ||
|
a898a5996e | ||
|
d501bb8d52 | ||
|
7ab8ff56b3 | ||
|
eda36512ec | ||
|
04aee812f8 | ||
|
6718cce203 | ||
|
49f0bb6990 | ||
|
38afcbb21f | ||
|
87ab2beddf | ||
|
a05a34239d | ||
|
f11aba9648 | ||
|
c2ef119e50 | ||
|
8b6c99776e | ||
|
463bffaeb6 | ||
|
0cfd8032c0 | ||
|
144d5ff0cc | ||
|
ab5c65b08c | ||
|
6b33bf3961 | ||
|
89eb395e2d | ||
|
d671d48869 | ||
|
ed582fae91 | ||
|
4d5c3ee0aa | ||
|
02046fcdb4 | ||
|
fbe27749a0 | ||
|
eddab96a69 | ||
|
ed3376352d | ||
|
dfbb763031 | ||
|
5cf13d9273 | ||
|
5ef45fd12e | ||
|
8a293a41f5 | ||
|
931820a170 | ||
|
e9944b964a | ||
|
dbae1d2f8b | ||
|
0dc8feba05 | ||
|
5c7c2347f7 | ||
|
d069907948 | ||
|
725ab477a8 | ||
|
d05ee9ff60 | ||
|
3c1f6d97cc | ||
|
5fe827f6c4 | ||
|
76f9a93ed7 | ||
|
df2506bfbb | ||
|
b25ab04d2c | ||
|
6f094e8a54 | ||
|
e18ffc53f2 | ||
|
0eea3176d6 | ||
|
4f20977a8e | ||
|
5bd63bb56b | ||
|
f7103da818 | ||
|
bf4922a7ef | ||
|
6f7eac5c6d | ||
|
d6e73a89f3 | ||
|
269aefd405 | ||
|
a6865f1639 | ||
|
f55aa0b86e | ||
|
02b34f05aa | ||
|
37f42707e5 | ||
|
17f3ba1434 | ||
|
31dcc25ba5 | ||
|
4da93f6a5e | ||
|
5ed7d32749 | ||
|
ab5b9dbdc9 | ||
|
3b28bf07d1 | ||
|
b626c9b450 | ||
|
5430eca93e | ||
|
b41c477f44 | ||
|
5900413c08 | ||
|
c2ceab741f | ||
|
45ff4940eb | ||
|
9c8a15cb64 | ||
|
b09e54c961 | ||
|
f44b7e202a | ||
|
0f535e979f | ||
|
4c2c01b4f6 | ||
|
b1d48fe9a2 | ||
|
41590f91ac | ||
|
e9d1f4f46e | ||
|
7f287412ba | ||
|
2df094de2b | ||
|
964ab5b351 | ||
|
3f6e9a54fe | ||
|
4ec5d5ae1e | ||
|
c49b155c29 | ||
|
fc602b1888 | ||
|
81421992a2 | ||
|
4ef31f9331 | ||
|
d7e304badf | ||
|
bf3f1b4b49 | ||
|
2ac0ff03fc | ||
|
d10553d624 | ||
|
b1dfc3cd23 | ||
|
696efe349e | ||
|
6a32722acc | ||
|
8eaec56c6b | ||
|
60d3c9342d | ||
|
4dc2433e8b | ||
|
2bd5039f28 | ||
|
8b1b14a704 | ||
|
5e674ce1d0 | ||
|
3656bcf752 | ||
|
39093fc2bc | ||
|
efa5838be4 | ||
|
1c6ad2fa66 | ||
|
af144e1b77 | ||
|
b451bfed81 | ||
|
3e32c50936 | ||
|
208b15637a | ||
|
c958cce769 | ||
|
602ec54579 | ||
|
fa2bfc5d9d | ||
|
94f906b34c | ||
|
60c93456c0 | ||
|
a4f210379d | ||
|
27e6205a37 | ||
|
3db6d82904 | ||
|
b8ddfd642e | ||
|
c98acd42db | ||
|
39f418f2d2 | ||
|
9fbd484dfe | ||
|
1773f2aadc | ||
|
cb1b72d6ba | ||
|
f5a2ec961d | ||
|
bf40e77d65 | ||
|
568bdef61f | ||
|
2303521778 | ||
|
3bf2946d13 | ||
|
484e5cb3e8 | ||
|
fbe8b6c34d | ||
|
4e7397dc9d | ||
|
a6189106e1 | ||
|
ed6123a3e6 | ||
|
0cd5deaa3f | ||
|
6c047e2678 | ||
|
405a480cae | ||
|
b4e69bab71 | ||
|
db81edfb2b | ||
|
24829bc44f | ||
|
c8594045df | ||
|
ea3f9b971f | ||
|
380974eed4 | ||
|
8151403bf6 | ||
|
16f5e76f00 | ||
|
b6b178cac0 | ||
|
0f020366e3 | ||
|
27a19be369 | ||
|
0c166eb307 | ||
|
79d73c28a7 | ||
|
2aed01b530 | ||
|
3fb0d61271 | ||
|
599acaf514 | ||
|
5f4103a4a7 | ||
|
c7c72231c7 | ||
|
6887a4419e | ||
|
db5cb6233c | ||
|
963829712d | ||
|
46ceccfbb3 | ||
|
aaf3039967 | ||
|
2509f18def | ||
|
a1e2d79613 | ||
|
96ba5c3983 | ||
|
041282190a | ||
|
8cdd5de75c | ||
|
a95c232f11 | ||
|
c9aba288b4 | ||
|
35a9d502af | ||
|
409c8783fe | ||
|
3adc3d7732 | ||
|
ec19712388 | ||
|
2c89e89c84 | ||
|
e602a464db | ||
|
ffc0651d89 | ||
|
7162efd836 | ||
|
8e7d782102 | ||
|
dc2028f99c | ||
|
f12ba5f7a9 | ||
|
45fb21e32d | ||
|
ecbb417736 | ||
|
3a59a862d5 | ||
|
e34fab0045 | ||
|
7254ebe0e3 | ||
|
b43bc3f32d | ||
|
ca3d13b5cc | ||
|
c8818bcce3 | ||
|
b234b5937a | ||
|
1bdef0f2f7 | ||
|
56fb61bd6f | ||
|
2c7d0b8909 | ||
|
cbb8d76da7 | ||
|
cce925c06c | ||
|
505a4bfc34 | ||
|
58e151966c | ||
|
8a6c9b7afc | ||
|
e72e2071b0 | ||
|
5d3af27928 | ||
|
5dc0bedbc4 | ||
|
8f7ae2665c | ||
|
10fdf819d3 | ||
|
02928601ef | ||
|
c227f6dc2c | ||
|
673f0224c9 | ||
|
79c602f59c | ||
|
07c070e253 | ||
|
9bda3bd477 | ||
|
2c9ad9562e | ||
|
c264ee22e7 | ||
|
f194a689cc | ||
|
a36b350954 | ||
|
db4278fb9d | ||
|
39ba4cff2f | ||
|
d68da74790 | ||
|
5fc45cd736 | ||
|
5ae2f3d081 | ||
|
478bf643bf | ||
|
7929895b11 | ||
|
da11a72b4c | ||
|
1649368cee | ||
|
a528d62c16 | ||
|
bd13dbdad0 | ||
|
8e7ffd9e16 | ||
|
f0bff09b5e | ||
|
0e959b3019 | ||
|
983cd9c3fc | ||
|
2236ca3e12 | ||
|
f3afa6a7d9 | ||
|
ce7e2e3243 | ||
|
13416825b1 | ||
|
6c664e7ba9 | ||
|
34359617b5 | ||
|
9e2696b9bc | ||
|
bf840e8bfa | ||
|
1f03c140f5 | ||
|
2de161ce0e | ||
|
1171106afb | ||
|
f57ae73071 | ||
|
59872b5698 | ||
|
7cd8ea00d1 | ||
|
4b2f38926a | ||
|
537c95cf29 | ||
|
81a5722708 | ||
|
c150b913ac | ||
|
3e4b67db6c | ||
|
d727f8ff50 | ||
|
9546bf1dee | ||
|
dd9ce34d18 | ||
|
73f2d972e4 | ||
|
7d699c6c35 | ||
|
21f23f67f4 | ||
|
8874ba2779 | ||
|
420538e6e7 | ||
|
8eb68b54d9 | ||
|
80202f33cb | ||
|
c24579bfb2 | ||
|
21256c4529 | ||
|
668626b920 | ||
|
cbfa3bb56d | ||
|
536fcf02d7 | ||
|
a8ac3acbbe | ||
|
7980155375 | ||
|
aa855e31c8 | ||
|
675ee8e813 | ||
|
50ccce7387 | ||
|
40b561ea69 | ||
|
a0f73bd30f | ||
|
1b7fcce42d | ||
|
4749af6e90 | ||
|
f7ad40263b | ||
|
e5b25bfa58 | ||
|
1d23adcda3 | ||
|
0216d36ab7 | ||
|
2bec20ad76 | ||
|
93c1245b0f | ||
|
72504d7619 | ||
|
320aa34d39 | ||
|
87f2a4242e | ||
|
9bf0cbd659 | ||
|
b1470fd9b8 | ||
|
08016dc3b6 | ||
|
7a448f5528 | ||
|
4ac23bf14c | ||
|
bc708dee30 | ||
|
2888e5748e | ||
|
88f0a33e69 | ||
|
3165f92b6b | ||
|
3bd0fca633 | ||
|
cdff10d281 | ||
|
e425741c34 | ||
|
20a367b243 | ||
|
fdded9e7ee | ||
|
7d29bff136 | ||
|
0abfbeed3c | ||
|
35b7c3038a | ||
|
46dd96a4b7 | ||
|
788232ca35 | ||
|
3b458738e0 | ||
|
2c8fc67ab1 | ||
|
9b3ed3ed72 | ||
|
c59197e87a | ||
|
03e3c88d8b | ||
|
39693786ef | ||
|
357c324df1 | ||
|
650482208c | ||
|
2acad4a78c | ||
|
65ee4e1916 | ||
|
275bbc81f0 | ||
|
beafcf74ab | ||
|
e47909bb3e | ||
|
0b3b9c2257 | ||
|
8fb7a7e4cd | ||
|
c5ed148c52 | ||
|
e774c710a8 | ||
|
d237180a98 | ||
|
d8b618f7c3 | ||
|
e888a95bd1 | ||
|
36c2404a46 | ||
|
ba673beb82 | ||
|
4b56701152 | ||
|
59227116f3 | ||
|
9b0975b2ac | ||
|
3a39a5caa3 | ||
|
93e270f379 | ||
|
98c81fa2af | ||
|
1bb32a05a9 | ||
|
5dd4b77270 | ||
|
737d1aac7c | ||
|
886feae4ca | ||
|
1dfe26f14f | ||
|
d66fcd23df | ||
|
bdfb47e999 | ||
|
10300cc478 | ||
|
ababa639b3 | ||
|
9f6569d658 | ||
|
24c22ebdc7 | ||
|
6c365fffde | ||
|
dbb80dd6c0 | ||
|
624834de9c | ||
|
d31995f878 | ||
|
017b1cae26 | ||
|
c09f15b0e9 | ||
|
68284bed74 | ||
|
9a44d668d6 | ||
|
67e0197a7a | ||
|
a5a8cfa17d | ||
|
60c3e701e9 | ||
|
b9b129dcf5 | ||
|
d882ab236a | ||
|
140cc0e486 | ||
|
6ac7c0f893 | ||
|
096d50617f | ||
|
9dd8c0cc4f | ||
|
de0fab86ec | ||
|
bb36dd3893 | ||
|
ada837ee95 | ||
|
67e73173f6 | ||
|
4b63829eef | ||
|
029411d3fa | ||
|
6ba033f934 | ||
|
3734fa948f | ||
|
336742e335 | ||
|
66ca424d3a | ||
|
2da0a91a36 | ||
|
fee1bde231 | ||
|
4a94430bf0 | ||
|
cc337f7b1e | ||
|
d8a06777fe | ||
|
9207eedbfb | ||
|
c97b832648 | ||
|
4ef629f79d | ||
|
0b4e3c3db5 | ||
|
f12cc523b4 | ||
|
5c3c9d2ed1 | ||
|
3ac3673326 | ||
|
1a3940575e | ||
|
16c8b1efab | ||
|
0e789be09f | ||
|
a948c7d69d | ||
|
d8ec0103a9 | ||
|
50161670ce | ||
|
c1f612dce1 | ||
|
6fb74482d7 | ||
|
4b680ffa5f | ||
|
c71c8d56ce | ||
|
295ae7b4bc | ||
|
839c884cef | ||
|
13ffe7acfb | ||
|
39a0c0d96e | ||
|
a95a542148 | ||
|
b3cb2ac3ee | ||
|
759fe54132 | ||
|
519a888e82 | ||
|
4f1e4e7471 | ||
|
7b8a32f630 | ||
|
92d91a65bb | ||
|
dab5289177 | ||
|
a77cb1e579 | ||
|
01bdda0ae6 | ||
|
fbe35e6e6b | ||
|
a3cd74e30b | ||
|
dbd4781de1 | ||
|
6d48316436 | ||
|
cca6965cd1 | ||
|
dd63ed7e69 | ||
|
61e2283146 | ||
|
97eb768748 | ||
|
be8b5a8aeb | ||
|
99ed39b26c | ||
|
48a0eb90a7 | ||
|
3c342077d6 | ||
|
f1bef1e7e6 | ||
|
da9749ecce | ||
|
fa7be597d2 | ||
|
53da418d68 | ||
|
897ed7e381 | ||
|
daf0939f09 | ||
|
7b1d6ddcf6 | ||
|
267e1dd0f8 | ||
|
c9d0bfce54 | ||
|
7f9e5e29a8 | ||
|
d0f685183d | ||
|
bed77bd356 | ||
|
bc0e3b254b | ||
|
47bf0ebb47 | ||
|
0acb95bbd5 | ||
|
8665f4a251 | ||
|
3adacb8799 | ||
|
76aa69b9ac | ||
|
78116f1596 | ||
|
36693b7d9d | ||
|
8ce68f93ea | ||
|
3512cb9599 | ||
|
ea164a2030 | ||
|
929ba70ef8 | ||
|
5b2113c43d | ||
|
6df2c0bab5 | ||
|
1c5193aa4d | ||
|
bd55fe868d | ||
|
87a2465a25 | ||
|
5f839ad3ee | ||
|
1663d8dfa9 | ||
|
08eafc54e6 | ||
|
fe1d8b137e | ||
|
39c0826f3c | ||
|
bf63b0993d | ||
|
f91a1363cb | ||
|
a2c9aa7662 | ||
|
d135da6c1d | ||
|
d27051f04d | ||
|
b28fa2a1ad | ||
|
77a91f5a8f | ||
|
dcc7ee98b3 | ||
|
30edb2a44f | ||
|
f63332a7aa | ||
|
86c37ce192 | ||
|
93e6c9e5a0 | ||
|
92e1fa4d3a | ||
|
bf7d292884 | ||
|
add8db0186 | ||
|
3e62c6ae2f | ||
|
cd4aa8ccd6 | ||
|
937dbdc71f | ||
|
66a7b508b2 | ||
|
a5493f7947 | ||
|
979c4907da | ||
|
b8f6fdeb2b | ||
|
067376cb3b | ||
|
bdbe9255a6 | ||
|
c460e1bbbe | ||
|
7e2b72fa5e | ||
|
6ee6a8a74f | ||
|
80984c94a1 | ||
|
1757b66467 | ||
|
8aa25af014 | ||
|
5a0e47be48 | ||
|
756a866ffd | ||
|
29305be23b | ||
|
8253cfd21d | ||
|
165a00896e | ||
|
2149ea1306 | ||
|
90547da007 | ||
|
9ec4881d8d | ||
|
487593af38 | ||
|
4e8f878d83 | ||
|
af6544c64d | ||
|
09e1f53b3e | ||
|
1c4f191f42 | ||
|
a37bd824d5 | ||
|
2c79173d20 | ||
|
eb45b89557 | ||
|
bf8c345341 | ||
|
ef46280716 | ||
|
2453e1284f | ||
|
95bcb272e0 | ||
|
e0e61b5262 | ||
|
3ddef56167 | ||
|
f8e6fb81d6 | ||
|
683ec87adf | ||
|
23edbe5ce7 | ||
|
6ff32a51e3 | ||
|
4cbac3a864 | ||
|
94a99b5bec | ||
|
810bf06e16 | ||
|
1254667b2c | ||
|
053eb8a0fd | ||
|
82ef380256 | ||
|
44449d8e72 | ||
|
6c3a0890c7 | ||
|
8c0def7c79 | ||
|
de77751779 | ||
|
cdf809926b | ||
|
d40341f1ad | ||
|
4a94fb91d7 | ||
|
24ea9ca947 | ||
|
98eb9bf2bd | ||
|
1eb30cf3ab | ||
|
6fd7c0ff8e | ||
|
263e81cb2c | ||
|
92ebf37d86 | ||
|
a10e406131 | ||
|
21095e80a7 | ||
|
55ae43ed03 | ||
|
9cc934a972 | ||
|
cdfec7ebb4 | ||
|
59ad69b637 | ||
|
ca6b759607 | ||
|
f9d857211f | ||
|
01ad8661d6 | ||
|
d21b8166f0 | ||
|
63582bb489 | ||
|
c19f2de3a8 | ||
|
d2e7b61eb2 | ||
|
13a448ebfe | ||
|
bad2e1f9c4 | ||
|
8edac51401 | ||
|
f34ba9bf96 | ||
|
82aea946a2 | ||
|
a0665dc431 | ||
|
e32d6cdecd | ||
|
23b43319a8 | ||
|
e7a7a18c43 | ||
|
8e5abcf5c2 | ||
|
e08e8641cb | ||
|
3e8f3cfb49 | ||
|
1eaaa5c6d3 | ||
|
1cc776d332 | ||
|
4009ae7d77 | ||
|
07506faa3a | ||
|
4d787ec93c | ||
|
188413a531 | ||
|
ad55c9cc19 | ||
|
9b3ac49298 | ||
|
4306b0caba | ||
|
ebd1baa42c | ||
|
6861bbed79 | ||
|
25f66e6ac0 | ||
|
838519e89f | ||
|
be4641b8f3 | ||
|
e861cab727 | ||
|
f8f87ec091 | ||
|
c0f1996478 | ||
|
106746ce58 | ||
|
62773fa88a | ||
|
28a8ed62f3 | ||
|
110751e992 | ||
|
0d447c9d50 | ||
|
827d6d1d2d | ||
|
a64972fe38 | ||
|
09bdc81aeb | ||
|
c057de3a3c | ||
|
1c4aff3ee1 | ||
|
6bfed5c98c | ||
|
f01231277b | ||
|
94534f714c | ||
|
1f9c06e606 | ||
|
711c448242 | ||
|
0c6a640e50 | ||
|
11d9a71e5d | ||
|
eed842fff1 | ||
|
49fafcc68a | ||
|
c46cccc3cd | ||
|
dd714cc95e | ||
|
f9ce8fa368 | ||
|
4fc872a4cb | ||
|
c8556f69e7 | ||
|
0b3f660626 | ||
|
7fa359764d | ||
|
2bc642ae6f | ||
|
5228aa5e5c | ||
|
d9c61a37bb | ||
|
5f662988ff | ||
|
87c9c0c3b1 | ||
|
0ede15dcbf | ||
|
8ceecec5b8 | ||
|
28ff138370 | ||
|
e8acb48b1e | ||
|
b588bd6e4f | ||
|
d9fd2c28b0 | ||
|
0a02ed2a39 | ||
|
b13e1b3d44 | ||
|
98732cb033 | ||
|
eaa4a43458 | ||
|
6af6b73c89 | ||
|
990987ac92 | ||
|
fd8f5b9ff0 | ||
|
062b61affb | ||
|
311aa74dd3 | ||
|
0704c3ccb9 | ||
|
d375dca1f1 | ||
|
5f04a6239e | ||
|
6f9c99ac6c | ||
|
3c50b00a9a | ||
|
ce8893ef6b | ||
|
5fb7bb50e0 | ||
|
15bd5bf6f6 | ||
|
b35c1d852e | ||
|
93ec127245 | ||
|
42613dbcf8 | ||
|
a9ec5f5c38 | ||
|
10b04f41df | ||
|
8a16504988 | ||
|
703e51d500 | ||
|
f97d6b552b | ||
|
f592c64c6a | ||
|
5d5355bc41 | ||
|
f02c14d327 | ||
|
ca4f971eb4 | ||
|
e43bf3b05a | ||
|
38e7dcfd12 | ||
|
6ccb4b726a | ||
|
ecf167e889 | ||
|
dce819f57b | ||
|
fe7328b92e | ||
|
46fa9e6b82 | ||
|
76712439ee | ||
|
5a2830a654 | ||
|
b34ca9a521 | ||
|
7fc4a65868 | ||
|
85899a59c0 | ||
|
73214be565 | ||
|
175a87f948 | ||
|
201aab9f73 | ||
|
0581d614f6 | ||
|
9622a11b2e | ||
|
f17c5bc334 | ||
|
ed9f40fc4c | ||
|
31a58a21c6 | ||
|
061ece55f3 | ||
|
391f278ee5 | ||
|
004b323fd4 | ||
|
088cfed794 | ||
|
908f649ea7 | ||
|
c214adcdf0 | ||
|
097ba07f20 | ||
|
0c04373b79 | ||
|
dd8f1800df | ||
|
81b918c392 | ||
|
43038564fe | ||
|
bcd77de328 | ||
|
0d90d6586e | ||
|
2324bccbe7 | ||
|
0cb07f511a | ||
|
e22fb444d3 | ||
|
9a09c1b027 | ||
|
a94968b6bb | ||
|
3ac05f1fa9 | ||
|
ad3effa7d1 | ||
|
d094c0d2b3 | ||
|
157e7f9f78 | ||
|
5816342bed | ||
|
22491afa58 | ||
|
a023b71ce0 | ||
|
392848c885 | ||
|
a815661de1 | ||
|
ff6261ccc8 | ||
|
7e68368d0a | ||
|
f21c8d895f | ||
|
120e17fa1e | ||
|
42e6ac4f6d | ||
|
7a77a3d7ce | ||
|
bf9b35d670 | ||
|
e0a14cdeea | ||
|
099a3f4f90 | ||
|
4d41f82794 | ||
|
1d24bfb99d | ||
|
47b809c7b7 | ||
|
f3f6cb03e6 | ||
|
a301d51fb2 | ||
|
d6703b20d3 | ||
|
8c4b076746 | ||
|
356e09091d | ||
|
d4c9841e44 | ||
|
bea13d039f | ||
|
1f8fd52103 | ||
|
94506c3c90 | ||
|
515771553f | ||
|
e204812d2b | ||
|
ca703cb858 | ||
|
b018d4a97d | ||
|
146768ff8a | ||
|
ea7473ed67 | ||
|
0e8393766f | ||
|
7d2536c503 | ||
|
f9cbf1b30c | ||
|
d66d87d271 | ||
|
5a8fa6cf38 | ||
|
76340035db | ||
|
0a26e68d0c | ||
|
14127b910f | ||
|
ba4d081021 | ||
|
18d65d513e | ||
|
3cf9e2d9f6 | ||
|
080842e44c | ||
|
49d534e779 | ||
|
5a0ef149a5 | ||
|
d2eb0e1fde | ||
|
2d90ffcbf0 | ||
|
5580c3fda0 | ||
|
10d26bf734 | ||
|
57ef175050 | ||
|
275c86a0a9 | ||
|
5fa6202111 | ||
|
1e001469f6 | ||
|
4251389c12 | ||
|
6ff2ce1895 | ||
|
1abc953cad | ||
|
c696a3b789 | ||
|
5986646af4 | ||
|
5674c1d82f | ||
|
c1c0a281cf | ||
|
84d4a1ce34 | ||
|
8a4d72e3b1 | ||
|
a7b5e4323e | ||
|
409f1bb644 | ||
|
1d5821abca | ||
|
b3eca73e48 | ||
|
7694326a4e | ||
|
9c026bc442 | ||
|
b812306bd7 | ||
|
0e667dfe36 | ||
|
9037421a85 | ||
|
1a9c6deb0d | ||
|
f08d2716ae | ||
|
f37c0e0548 | ||
|
be2c3217dc | ||
|
937d15d7e1 | ||
|
35ff3afa12 | ||
|
536d702d96 | ||
|
420070a1ee | ||
|
cd4a13ca55 | ||
|
9d0701a62b | ||
|
7c9a198c6d | ||
|
065577c9ca | ||
|
8533f853c8 | ||
|
2f60395ba9 | ||
|
906cecf087 | ||
|
cb1b917aa6 | ||
|
006d511d47 | ||
|
f6270d9cfc | ||
|
72f1c358d9 | ||
|
3cbadb1bd2 | ||
|
5d058c29a2 | ||
|
4964470e9c | ||
|
f4dfe7868b | ||
|
82e9792b4d | ||
|
af41a41046 | ||
|
59e5eb9a1c | ||
|
a0637a6ff8 | ||
|
5497697cf2 | ||
|
b07682e43c | ||
|
0bc572787a | ||
|
15fc4a8ae4 | ||
|
8bf7243549 | ||
|
66395d5fe5 | ||
|
f9509d2b38 | ||
|
7c50b8185d | ||
|
350a27575f | ||
|
494511e099 | ||
|
11ac8f8006 | ||
|
bcac851677 | ||
|
c294130080 | ||
|
c0f19dd963 | ||
|
e5a07da0c9 | ||
|
1ad3a96643 | ||
|
ac6d893758 | ||
|
9f2bdca9ad | ||
|
c5046f7809 | ||
|
f7897bbd64 | ||
|
6442625a9d | ||
|
5d079aacd6 | ||
|
0e7297873c | ||
|
dfb94d8917 | ||
|
ed445d0ab8 | ||
|
dddc1906c2 | ||
|
144454b8c3 | ||
|
8ae8fa7ec9 | ||
|
1ff1b82fc7 | ||
|
5d590bc2cf | ||
|
866f1e70a4 | ||
|
e273148a89 | ||
|
c5f8d823ce | ||
|
25e887b457 | ||
|
aac5ac6057 | ||
|
36a1eaedcf | ||
|
bb9f534259 | ||
|
cf9e5ae5a0 | ||
|
d2db25c7dd | ||
|
2542ddd30a | ||
|
260d919f80 | ||
|
fa8284d360 | ||
|
fb7bed2ea0 | ||
|
84b2c74057 | ||
|
a14cb13194 | ||
|
78fce90178 | ||
|
a158e893e0 | ||
|
117bc67a4c | ||
|
9930473390 | ||
|
b41ef73ecb | ||
|
52b6574240 | ||
|
0d857d3e6a | ||
|
3ba3fbf4a5 | ||
|
c3e7fcc153 | ||
|
2c00cd489e | ||
|
df52f3f0e1 | ||
|
11e8e56e05 | ||
|
a5ecbd547c | ||
|
866912d3f7 | ||
|
56e550f136 | ||
|
1e179adcf2 | ||
|
c5fe7ea0ea | ||
|
fdda0cc9cc | ||
|
f9dfc64c6f | ||
|
f41494b7cc | ||
|
821d9abc56 | ||
|
f5b55d5eb3 | ||
|
cdb1b1df15 | ||
|
8e6b41e637 | ||
|
1f7cc5f5ec | ||
|
1a0c3a49b9 | ||
|
c4e2e9c4f0 | ||
|
7df973648c | ||
|
25aea140be | ||
|
8d2cf0cf38 | ||
|
d2bbfe1282 | ||
|
6d72391ee1 | ||
|
a53e02b51b | ||
|
401e334c28 | ||
|
4c10ce6f40 | ||
|
fed6a4689f | ||
|
6dc5a9efde | ||
|
cb1e5a2412 | ||
|
f47a012c62 | ||
|
e6e22dc0bf | ||
|
d8589113c3 | ||
|
188e503070 | ||
|
e4f7ac6236 | ||
|
7178943223 | ||
|
27c76e746a | ||
|
de47776ea5 | ||
|
7e56b595a0 | ||
|
d15a9a4359 | ||
|
c4ff3f731b | ||
|
886399284b | ||
|
bf73e09918 | ||
|
fef36e677d | ||
|
441fdc35b2 | ||
|
801c73ef94 | ||
|
3e56185a39 | ||
|
caf85fe61d | ||
|
3112682923 | ||
|
edb30af441 | ||
|
b5a6bb74ce | ||
|
8236a9529f | ||
|
c50d0646ab | ||
|
1484a9c0ee | ||
|
abe02c3843 | ||
|
8e9e738bb8 | ||
|
bd97a0dfe3 | ||
|
9a59cba7f3 | ||
|
07021dbd65 | ||
|
8ee8421af7 | ||
|
f983446355 | ||
|
6650d32055 | ||
|
0badff98c6 | ||
|
1630bf5de7 | ||
|
2b2820018c | ||
|
8540343d7f | ||
|
e52b347b18 | ||
|
67e0ccf677 | ||
|
ba6bcf86ca | ||
|
6952d2420f | ||
|
a85d7af9e7 | ||
|
39e63aee0c | ||
|
9176994947 | ||
|
d389b55f40 | ||
|
0ccff9fc54 | ||
|
a8836ca7b6 | ||
|
f5d04a970f | ||
|
7aec98dafd | ||
|
773564d4f5 | ||
|
3e2edc1a2d | ||
|
6a12a24d73 | ||
|
9cfc9b9baf | ||
|
1739647768 | ||
|
92b67ead83 | ||
|
ee9525cc00 | ||
|
571bfaf5d7 | ||
|
a3475607b2 | ||
|
f0a653d010 | ||
|
eecdf66013 | ||
|
f99db05a4a | ||
|
635731421f | ||
|
44743df7d6 | ||
|
33617694cc | ||
|
ed445d20b9 | ||
|
66c2fe091b | ||
|
8c80f47a35 | ||
|
e37025c1c7 | ||
|
0aabde081b | ||
|
a1c9d53474 | ||
|
094996ad0c | ||
|
ce359a7689 | ||
|
ee599160b3 | ||
|
dd076f7a13 | ||
|
3021d38b6f | ||
|
bfcabeaf26 | ||
|
c31e0336dc | ||
|
a1e42cac7a | ||
|
14a3e5b771 | ||
|
5901c543da | ||
|
456b80e6ae | ||
|
e5644ae011 | ||
|
41c794c733 | ||
|
a481448d46 | ||
|
2bd7ce618a | ||
|
da1ac4f1e9 | ||
|
f0cb638106 | ||
|
dad2396d01 | ||
|
91e4d8b663 | ||
|
e35496133e | ||
|
3be808ae1e | ||
|
c5772916a1 | ||
|
8cd63b80b1 | ||
|
c087654386 | ||
|
60b9e65c78 | ||
|
79b304a5d2 | ||
|
bb9fd126e5 | ||
|
bff2d5c26c | ||
|
46d9ac8380 | ||
|
5da3ca4bb1 | ||
|
2c99fdc092 | ||
|
31a075fb13 | ||
|
1d132d7a1e | ||
|
3b6f88cfa7 | ||
|
b927763d8d | ||
|
d00e1cb6a5 | ||
|
adf7474edb | ||
|
041d663cb8 | ||
|
37f611a8d3 | ||
|
be99329efa | ||
|
327cb70bb8 | ||
|
be2b5a4c3a | ||
|
d1eda9dd73 | ||
|
b902cb5a13 | ||
|
1184ee4a59 | ||
|
2cf898afcc | ||
|
38fc0bd889 | ||
|
df53e19eda | ||
|
7f79b26341 | ||
|
63391717e7 | ||
|
554629f37a | ||
|
791c3cd955 | ||
|
6e53c93271 | ||
|
7097315079 | ||
|
d50758197e | ||
|
9ff35d5a5a | ||
|
00f7bdbfaa | ||
|
e682d3461f | ||
|
71898d0c8c | ||
|
416ead5311 | ||
|
c7882450ac | ||
|
1eea5b8a58 | ||
|
7341337b5f | ||
|
964d87ae10 | ||
|
cb02c723e0 | ||
|
4c1b7add39 | ||
|
252aa1410b | ||
|
64693eaca2 | ||
|
c39a1596d5 | ||
|
46184188e4 | ||
|
d9f4f424fd | ||
|
6b3f18cb5d | ||
|
75c22b6a6f | ||
|
19e7fdfdb0 | ||
|
8ba14ef113 | ||
|
50025971d8 | ||
|
bcbba04f27 | ||
|
74ba8877d4 | ||
|
ec91d74456 | ||
|
cb014cf255 | ||
|
af08b73280 | ||
|
e86d568536 | ||
|
9f7eb36a1f | ||
|
0fcbfa996f | ||
|
2ab5e5d267 | ||
|
5b7bd6a52f | ||
|
ebb8ec954d | ||
|
dd856a9116 | ||
|
5e38bb7a32 | ||
|
f446e42317 | ||
|
67f67a02f8 | ||
|
a9aa5ad229 | ||
|
f504c27972 | ||
|
9b3f92e265 | ||
|
4efb747389 | ||
|
347440019e | ||
|
39891ffe60 | ||
|
9bbbb2cd3c | ||
|
2a171fb08c | ||
|
9f6412a976 | ||
|
8a6a13db0e | ||
|
fbec61662b | ||
|
9d7f0e77f1 | ||
|
983607e683 | ||
|
c3cbdd0eb9 | ||
|
b56fa7b406 | ||
|
dabc38dbff | ||
|
e6bba49bcd | ||
|
23a1046a8f | ||
|
7c6b517672 | ||
|
f6188949f3 | ||
|
ff1ea46c46 | ||
|
e8bc07d40f | ||
|
fa717699f5 | ||
|
8dfb8ebe5c | ||
|
7b6cac558d | ||
|
f13f4a4851 | ||
|
11245dbb82 | ||
|
805bed092e | ||
|
b38694fbcd | ||
|
ac7dc03603 | ||
|
253a5e3e4b | ||
|
b8131cee2e | ||
|
c8178ab915 | ||
|
577ae6923a | ||
|
fcaec2c3f4 | ||
|
78f4b28697 | ||
|
acd32b500c | ||
|
168d0f11ab | ||
|
6da8b69ff8 | ||
|
3fa460a42a | ||
|
021e7ce49b | ||
|
2d093e9692 | ||
|
30a244de7a | ||
|
195398713b | ||
|
3d1e57766a | ||
|
dd08381167 | ||
|
c096cc23df | ||
|
d8d000f279 | ||
|
5dd91db5c0 | ||
|
c97be4d0d1 | ||
|
fa53ec40d6 | ||
|
413a4cd7bd | ||
|
c22bbc5b91 | ||
|
6f45e376da | ||
|
5e6a38769d | ||
|
f5797e3799 | ||
|
bbbbd0810a | ||
|
053e2a52b8 | ||
|
99eb466223 | ||
|
2dec36f210 | ||
|
8b46c8bf20 | ||
|
77d83bffee | ||
|
666e8e133e | ||
|
959898e0fc | ||
|
d41b9beb71 | ||
|
00a037c786 | ||
|
d8b51b4f2c | ||
|
4d003f51c3 | ||
|
e01512e469 | ||
|
5836a85340 | ||
|
4e15556eeb | ||
|
0956dbb578 | ||
|
0c0ff855b1 | ||
|
017ba509a6 | ||
|
9d9b5af97f | ||
|
dd5e5323f1 | ||
|
cee7017d20 | ||
|
c9311ea3c9 | ||
|
92f08be416 | ||
|
4478f64002 | ||
|
b56e22d4ee | ||
|
d6ee10a543 | ||
|
217165208b | ||
|
2c664efb3c | ||
|
15a1a83729 | ||
|
c87415023c | ||
|
86fddf2ec1 | ||
|
1eb8d0fa1c | ||
|
6df77ef94b | ||
|
bff66dbbd3 | ||
|
646f457637 | ||
|
b37d9179e6 | ||
|
eff9d568a2 | ||
|
11793f04c1 | ||
|
79e8a694ad | ||
|
4a202eca59 | ||
|
70fcca824b | ||
|
f2e0190b68 | ||
|
20205d7ff4 | ||
|
3b195f61da | ||
|
99a40ae49f | ||
|
ba4ed5a1bb | ||
|
ac42ff5d73 | ||
|
4bb3d69631 | ||
|
e6aac6a77f | ||
|
bb4e8e5717 | ||
|
c963e280ca | ||
|
ea1ce6a263 | ||
|
412acf943d | ||
|
1984989564 | ||
|
e1988cd6fc | ||
|
6269ce36b3 | ||
|
9ab81eb444 | ||
|
b75ed5b8f1 | ||
|
fbd9502474 | ||
|
b32c4a8fbb | ||
|
3755f598a2 | ||
|
af7a9ff591 | ||
|
55376ea7f0 | ||
|
3a2843b9fa | ||
|
6dbfce0095 | ||
|
1613b3c0df | ||
|
00ee2b4478 | ||
|
9a0cb59830 | ||
|
54c4fb5f56 | ||
|
c3bf1dde7e | ||
|
963bba63d0 | ||
|
eac930ad7f | ||
|
4c175a3ed9 | ||
|
ec39ec69bb | ||
|
3107785947 | ||
|
fe130b62c8 | ||
|
f0363ac221 | ||
|
75936fcb9c | ||
|
ffbb894dd6 | ||
|
7271a64ac2 | ||
|
ee65f60222 | ||
|
c41e3cbf93 | ||
|
599076d6f4 | ||
|
06170592bd | ||
|
14111188c0 | ||
|
d185f230b9 | ||
|
079ba2a529 | ||
|
d99429463b | ||
|
563de82707 | ||
|
8c0e96e6e6 | ||
|
550858092c | ||
|
ae6add1e77 | ||
|
927943e07a | ||
|
4cfb1c573e | ||
|
a36b516070 | ||
|
cb0ae29308 | ||
|
6ee452aef3 | ||
|
bce274155c | ||
|
019aff88ca | ||
|
c87a2ca335 | ||
|
4e650ec1ba | ||
|
7ec911c4df | ||
|
605aaf955c | ||
|
e78a3f7939 | ||
|
54401bc0a5 | ||
|
a02ef0dbc8 | ||
|
34c464e8d0 | ||
|
32570c59c8 | ||
|
4721f8ef5f | ||
|
3c458353f0 | ||
|
59e3c4874d | ||
|
4693f436a5 | ||
|
b4dfd08bc4 | ||
|
3cda93d001 | ||
|
e705ca83b2 | ||
|
f90ed9e9db | ||
|
808d93d767 | ||
|
0d795aad16 | ||
|
3e8bc98f23 | ||
|
546d0b25b0 | ||
|
1f04723d8d | ||
|
cd78e2fc43 | ||
|
f6850c36fc | ||
|
8f96256e86 | ||
|
4404fb72bd | ||
|
8ae3b430c8 | ||
|
e6bc1f0730 | ||
|
747f7a1b04 | ||
|
01e7c45664 | ||
|
65c0d49c3b | ||
|
cba9e5845d | ||
|
c6e5011a98 | ||
|
229ad8be83 | ||
|
d58b2d1b32 | ||
|
b69f2856bf | ||
|
76a59338eb | ||
|
4003e93999 | ||
|
fe9ae0d8bd | ||
|
0326e58c8a | ||
|
c043142b86 | ||
|
c28edb1117 | ||
|
204bea8947 | ||
|
39e65c8586 | ||
|
e54031e318 | ||
|
24fbc366a6 | ||
|
c104e66964 | ||
|
00df42ba39 | ||
|
c4fb4eb61b | ||
|
a9495aceb4 | ||
|
0999297e58 | ||
|
62ae2a3bd5 | ||
|
213cc14494 | ||
|
59ebb94d24 | ||
|
a11b32dae5 | ||
|
0177facbf0 | ||
|
b8d252273d | ||
|
b942569ce0 | ||
|
275b9ce718 | ||
|
58d0dbb542 | ||
|
f84a01d840 | ||
|
6ee03460d6 | ||
|
d01fb914a9 | ||
|
2182bc3af2 | ||
|
d9b077154e | ||
|
7e6c106869 | ||
|
c3e37ef9a0 | ||
|
8bbbaae290 | ||
|
79de27544c | ||
|
2cbf53ad7b | ||
|
c52607b465 | ||
|
087566072d | ||
|
6b814afd39 | ||
|
ea8aa6b07d | ||
|
1b0f731e30 | ||
|
1ebde4a880 | ||
|
e53bd477b4 | ||
|
3f9287c36b | ||
|
b2b940fc32 | ||
|
7d9e170512 | ||
|
6ab92abe80 | ||
|
e30db943db | ||
|
e2b4a24a35 | ||
|
20e3291eb9 | ||
|
ebfa2fb1d0 | ||
|
ae8219dc97 | ||
|
64ea02983b | ||
|
f1b6ae8784 | ||
|
8b9b65d3f1 | ||
|
e82368ec85 | ||
|
d1bee8fe61 | ||
|
07704b8511 | ||
|
6a44d66fed | ||
|
10895514c6 | ||
|
1290f18ed4 | ||
|
49e634a62f | ||
|
8754b54d81 | ||
|
c191a7cfdb | ||
|
6eb49991a4 | ||
|
1dd59375f6 | ||
|
c3f0f30910 | ||
|
10c033e580 | ||
|
48a07d531c | ||
|
80582a128a | ||
|
db494de809 | ||
|
68d58212a9 | ||
|
48a6dabc5b | ||
|
0ae0047246 | ||
|
49dec1577e | ||
|
4e30bf705c | ||
|
4e9a91d03f | ||
|
2f8c9d4f93 | ||
|
0f29fd3e10 | ||
|
58f786f6d0 | ||
|
e2b1ef053f | ||
|
0bbca596a9 | ||
|
09014e3390 | ||
|
c634f6067a | ||
|
255cf6b305 | ||
|
07bc9f6477 | ||
|
464da23d4e | ||
|
a2c85a0ac2 | ||
|
f837369ef0 | ||
|
153b3fbfc8 | ||
|
c7739a7760 | ||
|
41fcf58b80 | ||
|
13e7af7762 | ||
|
c38f23400c | ||
|
62b449e52c | ||
|
85ae66d276 | ||
|
e15ae6bea3 | ||
|
bbf8a49ac8 | ||
|
b95fc7e782 | ||
|
7cd4f78767 | ||
|
49882112ac | ||
|
c957c7a515 | ||
|
045d96cdd1 | ||
|
a218f4adc3 | ||
|
9ba58233ec | ||
|
4aedf662e9 | ||
|
59e486848c | ||
|
4cef435089 | ||
|
d128ba544f | ||
|
372a827ecd | ||
|
0eec6447e4 | ||
|
13d72ac833 | ||
|
abf3da2fa1 | ||
|
df8269e772 | ||
|
19535b48ab | ||
|
da68c48723 | ||
|
44523168d7 | ||
|
2b50f65c49 | ||
|
14c2778558 | ||
|
7878d2804f | ||
|
cef56bd7ef | ||
|
c02a3371d0 | ||
|
c2c48bbc9c | ||
|
131fdf6898 | ||
|
a2e4de2d0d | ||
|
7d3d693fe8 | ||
|
94df3e931a | ||
|
2e225dfc3a | ||
|
409d7b3652 | ||
|
c658dc0ffc | ||
|
13e4cd4a49 | ||
|
609d410e6a | ||
|
04860ae1d2 | ||
|
a0a90f03a8 | ||
|
be3a883c51 | ||
|
0fde5c21b7 | ||
|
c4cc9f8489 | ||
|
ff7bc13058 | ||
|
ddea61148f | ||
|
88ad7e98e0 | ||
|
a83d38a5fe | ||
|
a3b1a30d06 | ||
|
f8b192bd94 | ||
|
4c6ab3921a | ||
|
1dc1fd421b | ||
|
fed953023d | ||
|
5a4cdaf348 | ||
|
4d49cb2d18 | ||
|
5759539e08 | ||
|
74441d2771 | ||
|
da0ebbe57c | ||
|
d8d392990d | ||
|
5db4a73d8e | ||
|
829af75416 | ||
|
acb0aeaa9a | ||
|
dc7c909316 | ||
|
a052e15319 | ||
|
c306ebed49 | ||
|
301701176a | ||
|
2ab66f62fa | ||
|
a50b299a82 | ||
|
a6808a8fda | ||
|
f5bd81e0d9 | ||
|
c265c91ef2 | ||
|
3184951625 | ||
|
c6fa160c02 | ||
|
e2eb986c7c | ||
|
9219339762 | ||
|
fac3d575c9 | ||
|
db9257f9fa | ||
|
bb21c87852 | ||
|
f0df25f824 | ||
|
7ac944c537 | ||
|
7d3dd2dd6b | ||
|
48538ef5d5 | ||
|
acd3710469 | ||
|
56e79de707 | ||
|
781c3eed2f | ||
|
d0d8de94dc | ||
|
4974202bb4 | ||
|
2dce115732 | ||
|
ce1d4282db | ||
|
befc730769 | ||
|
3f7c6055d4 | ||
|
5ed7efb01d | ||
|
f0f924a0a2 | ||
|
a19a069b21 | ||
|
a43bfdef1d | ||
|
7994729742 | ||
|
f24523e93b | ||
|
98a8430f26 | ||
|
273795b025 | ||
|
f6c7ade579 | ||
|
84a4fe7b03 | ||
|
583ce7dc46 | ||
|
81d7d2a70a | ||
|
689372b572 | ||
|
083be5d0a5 | ||
|
4726dc96d4 | ||
|
3308de95f0 | ||
|
ea115e0481 | ||
|
2fdde24024 | ||
|
d21d6c2e4a | ||
|
4c1863d318 | ||
|
b8a00bfbfb | ||
|
4cd6813d16 | ||
|
21266e1c68 | ||
|
201b8d9ebf | ||
|
2440023dd7 | ||
|
5f3e70f915 | ||
|
5365439fd4 | ||
|
9c28a4e8a0 | ||
|
565203047c | ||
|
b9795a2ae7 | ||
|
3f1acdc9ec | ||
|
f053e5ca38 | ||
|
9873371413 | ||
|
2a2af01d12 | ||
|
4e4f8ee3a4 | ||
|
b8fd921c81 | ||
|
fcf91954ff | ||
|
49708196ac | ||
|
8c8a2eef21 | ||
|
7790bb528c | ||
|
5bd2d27488 | ||
|
cd090ff000 | ||
|
47985a589e | ||
|
375d47ee3a | ||
|
e3e68dad36 | ||
|
40dbfab671 | ||
|
46405d7738 | ||
|
905ac20205 | ||
|
749a5b37c9 | ||
|
60079a14e7 | ||
|
df6edd09c0 | ||
|
88ff94dd69 | ||
|
067b81a60b | ||
|
03553b8bb9 | ||
|
bce7552d4d | ||
|
53a2777831 | ||
|
507492947a | ||
|
6d65d6bcf6 | ||
|
f4ab741445 | ||
|
c1fa3d99f3 | ||
|
fcc0eba7fb | ||
|
d7da3de096 | ||
|
0616bc7fec | ||
|
dd478fe681 | ||
|
c175a68a26 | ||
|
98a86c7636 | ||
|
4060705d87 | ||
|
1c11229510 | ||
|
7129868a56 | ||
|
4a6e3e0f5a | ||
|
b6a0a36d4e | ||
|
3b7ae1639c | ||
|
3fb7547d4d | ||
|
41b3eb9f79 | ||
|
f2c746122e | ||
|
e25a54aef4 | ||
|
5c42e45048 | ||
|
c8b92bc858 | ||
|
9d059fcfaa | ||
|
ce5f193219 | ||
|
92023ecbe6 | ||
|
1e0164a96a | ||
|
10c0633af9 | ||
|
6f5eac3143 | ||
|
60dfccb747 | ||
|
3460f460d1 | ||
|
bb70a0feb2 | ||
|
44eb4e0c9e | ||
|
97bbad7471 | ||
|
df6370dd61 | ||
|
ee8f4a5367 | ||
|
a5135cf2c3 | ||
|
41932b4501 | ||
|
028d1c6148 | ||
|
1efe418e05 | ||
|
4251ee1229 | ||
|
95a79130a2 | ||
|
e2518ab4d7 | ||
|
9d557f47b7 | ||
|
c654d3283e | ||
|
8e6b6269a7 | ||
|
a2404e7fb8 | ||
|
6321978f75 | ||
|
448dd61684 | ||
|
a3513b24ec | ||
|
57905efcd3 | ||
|
3052eca564 | ||
|
120f4adf35 | ||
|
b95dfe2b00 | ||
|
f02f0eae59 | ||
|
c5ebd53079 | ||
|
963b9d9a83 | ||
|
5bf5545394 | ||
|
2659097010 | ||
|
5f1470af9f | ||
|
4ceff8cabf | ||
|
b12f3e5aff | ||
|
f0b57e2873 | ||
|
f71baf3c73 | ||
|
d9bba25f67 | ||
|
eb1fe93a59 | ||
|
825bce32b5 | ||
|
36df9e0464 | ||
|
46480c5624 | ||
|
73fad671ed | ||
|
0d9f2aee70 | ||
|
805c717013 | ||
|
9fcb1da06b | ||
|
dcb6c9a133 | ||
|
edcb4eca22 | ||
|
de6ca56504 | ||
|
fdd9fca5b3 | ||
|
10805805fe | ||
|
e9dc09755e | ||
|
1ce2b18aaf | ||
|
abd351e326 | ||
|
d3e6069095 | ||
|
f0c3900842 | ||
|
25247de6a6 | ||
|
05288dad51 | ||
|
053ff33ef9 | ||
|
c97f1baa2b | ||
|
0f4c50e83c | ||
|
0a99c1c633 | ||
|
d6ae47a0de | ||
|
b258e6464d | ||
|
86a95013b6 | ||
|
636cba5d6b | ||
|
74931071de | ||
|
c92169cb20 | ||
|
927813ab3b | ||
|
060268747c | ||
|
47c953209d | ||
|
16df3eb995 | ||
|
454fb30759 | ||
|
4e157c2999 | ||
|
d96fd518e7 | ||
|
07fa1fa771 | ||
|
404b3fcd03 | ||
|
e1db5f3cac | ||
|
4bb768f39c | ||
|
f3a72dda7b | ||
|
b6af6ddea2 | ||
|
a2cd17ef0a | ||
|
b8ed449944 | ||
|
dc79299301 | ||
|
fa295b93a7 | ||
|
725c361e9c | ||
|
a8f25b1b93 | ||
|
3ee85b3356 | ||
|
22c85bf5f7 | ||
|
0a18838fb0 | ||
|
62629a0b34 | ||
|
b42848fd7a | ||
|
9070806172 | ||
|
4e11797d72 | ||
|
8f47b63762 | ||
|
daa13235e6 | ||
|
084c2d976e | ||
|
75363b609b | ||
|
8d09982f3b | ||
|
aa5e8eaf19 | ||
|
fc97eb8151 | ||
|
a68d7c9b9d | ||
|
730012edfd | ||
|
352987db7e | ||
|
92a6f231a9 | ||
|
a44bf164e5 | ||
|
5cc8cfb209 | ||
|
f99b7d8b78 | ||
|
e8fd97e355 | ||
|
5e64caa225 | ||
|
0672e1a1ea | ||
|
2deab9e0c2 | ||
|
ebe4ed99b5 | ||
|
dce51b02c8 | ||
|
70d4ee93f5 | ||
|
34a4372190 | ||
|
301543d3d0 | ||
|
c3c2bc51c5 | ||
|
40f808e9be | ||
|
3caf6c0e31 | ||
|
36a0c1b514 | ||
|
e128751e64 | ||
|
fae1efc237 | ||
|
dec03d4d25 | ||
|
064bbab3f5 | ||
|
f03e81544e | ||
|
4c8027aefa | ||
|
dbecd7a99c | ||
|
b035649c75 | ||
|
97ab595e20 | ||
|
20d4031ed4 | ||
|
812be801ce | ||
|
672a7ca740 | ||
|
0b3d69aa8e | ||
|
e87542e091 | ||
|
e9bbf773d6 | ||
|
68e8c968a8 | ||
|
a3f12329b3 | ||
|
f5ef213842 | ||
|
b573e5a2b3 | ||
|
17c3e7b238 | ||
|
9921a67a05 | ||
|
ad09197c00 | ||
|
be11d1cabf | ||
|
5399e2b648 | ||
|
a8d72cfdcf | ||
|
fbeee11fd7 | ||
|
545dae2e7f | ||
|
86891351f6 | ||
|
ddfe790995 | ||
|
85a9a8eca1 | ||
|
52c358e120 | ||
|
3bb13f76fa | ||
|
f57ce96ff0 | ||
|
105d7952fc | ||
|
6f4a488308 | ||
|
23a11dddb3 | ||
|
f516e538a8 | ||
|
4c28c1f556 | ||
|
b996bd3e65 | ||
|
6c1167df4a | ||
|
1044345587 | ||
|
d9eb419ecc | ||
|
8a266aac34 | ||
|
f6ac5dab74 | ||
|
d34ba16a30 | ||
|
5638e937b0 | ||
|
2ff88e7baf | ||
|
2e1732fadf | ||
|
57e041171b | ||
|
317b73ffaf | ||
|
39a9634a5c | ||
|
22ebc654a7 | ||
|
20c3b9b6f9 | ||
|
7588d83c6c | ||
|
efbb5bf9af | ||
|
dac69fafb8 | ||
|
8d98085873 | ||
|
8950e817e0 | ||
|
28aff1a90a | ||
|
9a56381e28 | ||
|
2d1708e5e8 | ||
|
73deb076fe | ||
|
c4f189863c | ||
|
02e15a4ce7 | ||
|
ba8e9bc168 | ||
|
46d3bda80a | ||
|
222006d106 | ||
|
7925aee91f | ||
|
4e3b012f3e | ||
|
b606b50cec | ||
|
57028a0807 | ||
|
840cc483b0 | ||
|
8d1f944096 | ||
|
a45c4ec8e9 | ||
|
0f3f50e817 | ||
|
a4ff292231 | ||
|
e8636670d4 | ||
|
bae6d679aa | ||
|
6fb1b53039 | ||
|
c81a4f8633 | ||
|
4599d1650b | ||
|
4edc3872ce | ||
|
8999e9f116 | ||
|
c5b4892596 | ||
|
46812777e2 | ||
|
616c0ebaa4 | ||
|
33d0343089 | ||
|
e6af8f63f3 | ||
|
cda62a4ff3 | ||
|
f359d619cb | ||
|
495faf5033 | ||
|
cba2daf314 | ||
|
2d68f9a986 | ||
|
7fde2e2fe0 | ||
|
bd4f3b0553 | ||
|
6373347d65 | ||
|
b458b204f0 | ||
|
dd3a3f821c | ||
|
60e3a1fc5f | ||
|
706a5680e1 | ||
|
cad87f51a3 | ||
|
66ab90b518 | ||
|
8bdd81ff24 | ||
|
f64e542879 | ||
|
7c58476af9 | ||
|
1f3b06a9bd | ||
|
e1314b6cda | ||
|
a6b629c392 | ||
|
f9f51e2381 | ||
|
ee75cba008 | ||
|
c768f03f71 | ||
|
20a57d6381 | ||
|
308f25fe4c | ||
|
9f2ba6bc2c | ||
|
b3b5d9602a | ||
|
2d16732972 | ||
|
94efd3e230 | ||
|
59a690f214 | ||
|
6f70a52880 | ||
|
85ebe5e01a | ||
|
a3ec4db9cc | ||
|
ffa6b5fcb2 | ||
|
b78a1f7b61 | ||
|
1d49c5056c | ||
|
83ebd601a9 | ||
|
a972e295ea | ||
|
7a0b4fc62c | ||
|
a3e3edb9a2 | ||
|
e66dd63516 | ||
|
ec66c7e534 | ||
|
2749b1f057 | ||
|
b079a94bef | ||
|
3d1bd626b0 | ||
|
60641d5a4e | ||
|
28d491e997 | ||
|
bb73529770 | ||
|
ebfd442b51 | ||
|
fdd8c0969b | ||
|
d78fcd2a29 | ||
|
2b2f5c9353 | ||
|
fcbb9dd8d8 | ||
|
b34f3ad5c5 | ||
|
8bdd909351 | ||
|
d7fe7f35ad | ||
|
1ebcc34e66 | ||
|
40e83dd9e0 | ||
|
18fd00d0c2 | ||
|
9ec26a9be5 | ||
|
3c0be47d3c | ||
|
26b5dab12b | ||
|
75ae6a8087 | ||
|
fb0e102d74 | ||
|
d777ec3267 | ||
|
cff9e9abab | ||
|
0b19831a7a | ||
|
27f3715780 | ||
|
76858f0534 | ||
|
bcfdfe93f9 | ||
|
7c6cc16ef1 | ||
|
bdc548b464 | ||
|
b60e6082f7 | ||
|
9a7254e4ee | ||
|
73e56e292a | ||
|
42a4a89793 | ||
|
bb7803b020 | ||
|
dd0fc0688d | ||
|
1380ed7328 | ||
|
9d6569d515 | ||
|
20be8fd2d3 | ||
|
9d48c77861 | ||
|
7ab93a70dc | ||
|
a435095e76 | ||
|
eb763563f2 | ||
|
9bf0b5bff1 | ||
|
638dd37545 | ||
|
11cc718273 | ||
|
cf6b07630b | ||
|
17e0db9da3 | ||
|
471c68f653 | ||
|
ae102f1318 | ||
|
2a0ad20188 | ||
|
9db5b481be | ||
|
185d00c86c | ||
|
e72ec07683 | ||
|
6e12726b11 | ||
|
6c539cd2d8 | ||
|
77642b9e3d | ||
|
86dc7111cb | ||
|
8d428acbbb | ||
|
1c13851858 | ||
|
a75ebc27c4 | ||
|
45f92dd981 | ||
|
5a6ce86476 | ||
|
7afad1dde9 | ||
|
b766d91f49 | ||
|
22dac266c4 | ||
|
5fb9537d6d | ||
|
c1b24e6ba2 | ||
|
cf803507d6 | ||
|
16e5271cac | ||
|
d5ad35630f | ||
|
1395baef01 | ||
|
90dcb02429 | ||
|
4f0211cdd8 | ||
|
a1e6d4b693 | ||
|
77db88ad28 | ||
|
c6a1b9fc39 | ||
|
9afd270111 | ||
|
53cf8628fa | ||
|
7d61cb1ef5 | ||
|
f53411b95a | ||
|
6d1e5886ec | ||
|
0a44c9456c | ||
|
fbf5d3966d | ||
|
0fa1478f90 | ||
|
d7ac53ae93 | ||
|
e7e86d7a32 | ||
|
3810c3cbaf | ||
|
f4c339db8c | ||
|
bb29c7a02f | ||
|
2699eb62bd | ||
|
866ffcf639 | ||
|
33d83e43de | ||
|
662a704165 | ||
|
083b586d19 | ||
|
fb91377139 | ||
|
6e4e5ba8c5 | ||
|
10b9e3b29c | ||
|
a1906b434f | ||
|
9d29307532 | ||
|
c638537731 | ||
|
6bf8ec2df0 | ||
|
18766905f4 | ||
|
a5b556b21b | ||
|
49efa4d47b | ||
|
bebd1dc235 | ||
|
771575cfc5 | ||
|
d6e34e0984 | ||
|
31d722f1ef | ||
|
dff0e2cc9f | ||
|
65abe1c875 | ||
|
2339211403 | ||
|
eccb7bb55f | ||
|
a5a54ab870 | ||
|
c021074db4 | ||
|
1c33561fbf | ||
|
b48c439bff | ||
|
a3c2a7e1e0 | ||
|
7e41b40441 | ||
|
e351f8ba07 | ||
|
1adaaf49cc | ||
|
e10d731049 | ||
|
242a3c6616 | ||
|
636ea82bf1 | ||
|
c5d562a56f | ||
|
2a0c779a02 | ||
|
3d4ac7ca63 | ||
|
161f37bb98 | ||
|
20030ab604 | ||
|
c66e2dc076 | ||
|
8d0e9eb8ac | ||
|
2dcd5e55e2 | ||
|
ab8e2d92c8 | ||
|
03968b44bd | ||
|
686d591f4f | ||
|
c53a760ba3 | ||
|
5e2955845a | ||
|
9a4a66b33f | ||
|
d2d3ab2d98 | ||
|
69ecdda5f5 | ||
|
b370893e58 | ||
|
86f8901c96 | ||
|
739165585a | ||
|
e3e7aec73c | ||
|
3995d001ec | ||
|
9dfabc3fb7 | ||
|
08bdf797f0 | ||
|
5e7d5c6312 | ||
|
354ee35ee4 | ||
|
c099f4f50f | ||
|
dc77b2d583 | ||
|
c9351fdeeb | ||
|
c1781cd793 | ||
|
ffa76dfd24 | ||
|
c8964a1c80 | ||
|
60807e5d4d | ||
|
0bf90d18ef | ||
|
d81e836b37 | ||
|
962b9915f0 | ||
|
31a1ad8409 | ||
|
a66e287903 | ||
|
2ee93d974d | ||
|
4e465a2066 | ||
|
412489c102 | ||
|
437bbe5c6e | ||
|
264927926e | ||
|
2ded9d551a | ||
|
fc37218311 | ||
|
27bed0cdcb | ||
|
741b025751 | ||
|
d661eee93d | ||
|
03bba6d0c3 | ||
|
7517948900 | ||
|
2fa7113787 | ||
|
c289248ac5 | ||
|
adcdb7a900 | ||
|
9dc84bfdca | ||
|
622f4975ef | ||
|
ade4ee810b | ||
|
81d5c22800 | ||
|
f699a69e83 | ||
|
9daf1b062f | ||
|
f78b4a0feb | ||
|
03d43cf50d | ||
|
d06d0a8f83 | ||
|
e15be0433e | ||
|
972dc89c0f | ||
|
b6fe3a3022 | ||
|
b9c28bed19 | ||
|
09ae0946b7 | ||
|
e3c438ff47 | ||
|
ca0f1ef8da | ||
|
b856f54333 | ||
|
ba5f1ac2a9 | ||
|
d3889cab9e | ||
|
9e703b8224 | ||
|
c9d3c3d369 | ||
|
77029b0197 | ||
|
589910b49b | ||
|
004941cc57 | ||
|
ef88425d25 | ||
|
283033f902 | ||
|
93aade6e8e | ||
|
9297011731 | ||
|
acebf1fb48 | ||
|
711e0ee503 | ||
|
4ac9b339a1 | ||
|
f2092ef083 | ||
|
c96d4991b9 | ||
|
58eccc1ed6 | ||
|
010a5d2829 | ||
|
5186605cec | ||
|
4c0fb04f61 | ||
|
06ea3a3014 | ||
|
615ec548db | ||
|
2df6824856 | ||
|
61ff40c299 | ||
|
31200040da | ||
|
450b682c5c | ||
|
4a66395d51 | ||
|
f1e8675756 | ||
|
1fdb34b1e1 | ||
|
2db927b7f7 | ||
|
99dbc99b6c | ||
|
ce70f4ebac | ||
|
3c9f51fbbd | ||
|
4869309997 | ||
|
fb45f4fcea | ||
|
d26c449d87 | ||
|
dbf080194b | ||
|
d82bff1bc2 | ||
|
9b96bc32eb | ||
|
59ecd47374 | ||
|
88c751df7a | ||
|
95053f7114 | ||
|
4949727cd5 | ||
|
08b0064ce7 | ||
|
c9571126a3 | ||
|
06d825d6c8 | ||
|
36e6ab4af8 | ||
|
ccec85f047 | ||
|
e8a5a75e96 | ||
|
4eb1fca68e | ||
|
fba24b8ead | ||
|
edfb9f3f6b | ||
|
2322d071e4 | ||
|
7658ed8eaa | ||
|
c81f280bc1 | ||
|
6e36febd37 | ||
|
b38c193fe4 | ||
|
b336cae118 | ||
|
991114eb7f | ||
|
d924fc5967 | ||
|
788d9571b5 | ||
|
714a1cc311 | ||
|
28c2df37ed | ||
|
4a424a6603 | ||
|
86d8ddd289 | ||
|
d0ed94ee8d | ||
|
eaa25a33d7 | ||
|
1d94e66b9c | ||
|
8eb76ea68d | ||
|
8a2dccddc5 | ||
|
84f19f7216 | ||
|
b2982c18bb | ||
|
f5852b4678 | ||
|
02ab2c1433 | ||
|
380019dd56 | ||
|
d2ab7dd9fb | ||
|
d101fb33b3 | ||
|
6d83a15ad5 | ||
|
95948e4eb7 | ||
|
8c4ea323ba | ||
|
f5697ad5d2 | ||
|
58770e5c79 | ||
|
77b2895b0e | ||
|
225266b687 | ||
|
9fafbbff81 | ||
|
e81a1f7acf | ||
|
691b2879bd | ||
|
8410c142ab | ||
|
de88068c66 | ||
|
0e0ac3efe5 | ||
|
2859c9fe19 | ||
|
939f2e41e9 | ||
|
9c6f903178 | ||
|
0fc7bc2762 | ||
|
efc1ff6eff | ||
|
11bb8e402e | ||
|
ef39ee1d5d | ||
|
52de26e67b | ||
|
df0c8064b2 | ||
|
9fcefca0f5 | ||
|
a579eef66c | ||
|
46f9e86f6a | ||
|
60eba6d783 | ||
|
4cb162a068 | ||
|
0bcaa73427 | ||
|
a1abea4e0f | ||
|
f11cdb4ab4 | ||
|
b7ba789370 | ||
|
ec311ecd2b | ||
|
14bc65e8e7 | ||
|
fb400af7d2 | ||
|
e3351db3d8 | ||
|
71f6537846 | ||
|
c8d20a8c23 | ||
|
8ef7cae36d | ||
|
a9d12608bd | ||
|
ef8b6e2805 | ||
|
1858c64e5f | ||
|
da3f18839a | ||
|
acd3b2d732 | ||
|
26651c18a6 | ||
|
d4efdcb78c | ||
|
43322bc3d9 | ||
|
438cbc99b1 | ||
|
0163f3d57e | ||
|
61de70c1df | ||
|
d67a1993d0 | ||
|
f7543cd0ba | ||
|
78d80fefc5 | ||
|
c8e3e2ce1b | ||
|
a75a513531 | ||
|
52aec885ea | ||
|
9b9edecaac | ||
|
c64222de4f | ||
|
5b1e4e0691 | ||
|
d12367a680 | ||
|
683a5b7120 | ||
|
5ad426d62e | ||
|
6d069bec19 | ||
|
3f4f2f4e2b | ||
|
ffa7e5a504 | ||
|
16221cfbbd | ||
|
a9b215357f | ||
|
5a52e4c71d | ||
|
432d44c20d | ||
|
7b9f295071 | ||
|
bed3fcfd43 | ||
|
49c9f843f8 | ||
|
52ef358e1c | ||
|
04e232096f | ||
|
abceed8112 | ||
|
ba48a86156 | ||
|
c759512c70 | ||
|
113a792734 | ||
|
b107b2c7bf | ||
|
9e37c14179 | ||
|
5f74dbcfc2 | ||
|
f8a53aea09 | ||
|
f9e7721653 | ||
|
2a36ec3e21 | ||
|
8158ca7c69 | ||
|
bb2c2d161a | ||
|
bd4bbb30ec | ||
|
ba3ba7b890 | ||
|
f4b324bbad | ||
|
3f13f6ed12 | ||
|
78459991bf | ||
|
3137f75221 | ||
|
d66c28dd6a | ||
|
02b3da8f80 | ||
|
f98b1d248a | ||
|
90aa9aa98f | ||
|
96b7fc9a75 | ||
|
7c5dc29981 | ||
|
90957dfedb | ||
|
286c22c0ed | ||
|
53d76355ec | ||
|
46c26e7942 | ||
|
705af35dd6 | ||
|
bd3efe57f7 | ||
|
118ceedda1 | ||
|
66d310977d | ||
|
20f7490fd9 | ||
|
0abde86cf9 | ||
|
f073e45575 | ||
|
79872b3e1d | ||
|
06cd86419f | ||
|
1164326d10 | ||
|
cf8955c71a | ||
|
f102d99004 | ||
|
5db3c6e47b | ||
|
af2798f063 | ||
|
d8e9d1c16e | ||
|
a923f15d17 | ||
|
6cd99e4ed4 | ||
|
9bfc2eaeb9 | ||
|
505fb3738f | ||
|
556deb4f77 | ||
|
24106114b4 | ||
|
5b22cfa9b3 | ||
|
aa736b2de6 | ||
|
37d527bd08 | ||
|
1b4ba68e18 | ||
|
d40464e5d3 | ||
|
32f02aa3c6 | ||
|
f7004188d2 | ||
|
9422cde275 | ||
|
94df0bd5ab | ||
|
52d349d776 | ||
|
83672ee28b | ||
|
a58b1ca6e4 | ||
|
0299fa1b68 | ||
|
91c1e75c00 | ||
|
c07db352f3 | ||
|
4fcfbd8134 | ||
|
41c1cfcef0 | ||
|
3e1da876c6 | ||
|
65fb688164 | ||
|
123b6b687e | ||
|
e8d5ebef7e | ||
|
c408fd0e62 | ||
|
803de40321 | ||
|
8254a643d2 | ||
|
992b810fa9 | ||
|
99a65d3098 | ||
|
1fcfe9e135 | ||
|
604c848dec | ||
|
41ffa8d6db | ||
|
184580257d | ||
|
76967e848d | ||
|
f93bcbaa84 | ||
|
cd95c133af | ||
|
7433d2eca9 | ||
|
90f691fa2c | ||
|
8b44c16b57 | ||
|
ef94fcf873 | ||
|
3ad6589f25 | ||
|
fb56c5875a | ||
|
7ff0d54291 | ||
|
1768daf98c | ||
|
7a9da6dde1 | ||
|
42f8d9d10f | ||
|
d56a7217d9 | ||
|
87240bb96f | ||
|
2062e49ae1 | ||
|
efdb1073a1 | ||
|
778729101a | ||
|
1f1ce67209 | ||
|
dccdb71b2d | ||
|
df0195bfe8 | ||
|
bb5640b41b | ||
|
72065768f3 | ||
|
3d43c22485 | ||
|
bafc42c8f1 | ||
|
21affac571 | ||
|
b18b532b40 | ||
|
9988c66d67 | ||
|
baa79303a7 | ||
|
b2d669ac3c | ||
|
28ece89272 | ||
|
7ba9d1fe65 | ||
|
31adb048f1 | ||
|
5864591150 | ||
|
c81d104822 | ||
|
b2401bf2e3 | ||
|
b471a6e519 | ||
|
d90cdf24f5 | ||
|
bc3a42c658 | ||
|
e40a853fdb | ||
|
c94bb6c1db | ||
|
b787c2617b | ||
|
3c99fad6b9 | ||
|
3981c87860 | ||
|
8ca3310401 | ||
|
5d2f8319b1 | ||
|
31f9687ba1 | ||
|
1dd1de2636 | ||
|
4d63bf473d | ||
|
dd10a833db | ||
|
d1a4838802 | ||
|
f8274cd5c2 | ||
|
931c8f9e66 | ||
|
6e6dae45d1 | ||
|
9b60a6c095 | ||
|
31b9c2fb60 | ||
|
8338075d03 | ||
|
1d425f3913 | ||
|
d90caf3e86 | ||
|
3f531c02a2 | ||
|
5075b8736e | ||
|
6bc2d11c5e | ||
|
5fcdcbf9b9 | ||
|
252ce2c95b | ||
|
12dbabb849 | ||
|
e2f1c60981 | ||
|
ac93570476 | ||
|
139765995e | ||
|
6bff6b562a | ||
|
a10d68e63e | ||
|
ec2db38516 | ||
|
39e720caed | ||
|
adf25b427b | ||
|
b74a6a64bc | ||
|
116733e1a5 | ||
|
1ff69825e4 | ||
|
4f53ffcd9c | ||
|
0281e95f2e | ||
|
de104b35db | ||
|
e2c6d2765a | ||
|
63929a1177 | ||
|
cf389681f6 | ||
|
3fb92bc245 | ||
|
b1ef91bcfe | ||
|
987b8af1b1 | ||
|
dbb6eaa9eb | ||
|
df434fc5e2 | ||
|
47657af173 | ||
|
bbe64e99e1 | ||
|
fdf460b82b | ||
|
6325a332bd | ||
|
0deb152bb2 | ||
|
8785a9869e | ||
|
16ac303994 | ||
|
06e7e377d4 | ||
|
dd77c6b59f | ||
|
8827b5510f | ||
|
1893545705 | ||
|
e9ac6b7482 | ||
|
799bc50c98 | ||
|
db8c379b93 | ||
|
989a90bb93 | ||
|
3d9aa60e4e | ||
|
93de46b50e | ||
|
da4f401d17 | ||
|
e7bb9a440a | ||
|
4aaba171ca | ||
|
97d0d91d2c | ||
|
37cdc6d500 | ||
|
adcb541b4b | ||
|
4efa147a2b | ||
|
bc8929d37f | ||
|
622e9aa3dc | ||
|
2588435c5c | ||
|
b262e1518f | ||
|
c5839604d5 | ||
|
01688946b3 | ||
|
2ec0d8e8ef | ||
|
219417cfb5 | ||
|
ca59805907 | ||
|
2190054abf | ||
|
4d04402ad4 | ||
|
2ae4989031 | ||
|
f3facac016 | ||
|
a9c479a78b | ||
|
c20d07c14a | ||
|
c8e2408f82 | ||
|
9557386b6e | ||
|
1afcbd02a9 | ||
|
6dfa6b0001 | ||
|
ecea251efa | ||
|
3a55cbc818 | ||
|
93f2b7c8a3 | ||
|
4d140d81f9 | ||
|
7fee61db84 | ||
|
84c20745a8 | ||
|
92099866e2 | ||
|
3601c531f4 | ||
|
a3155b2ad7 | ||
|
6eab5e3e14 | ||
|
dde989685c | ||
|
738818aa7a | ||
|
529e120313 | ||
|
351de1ca72 | ||
|
b73be2df6e | ||
|
b69b5aa82a | ||
|
861fcbe598 | ||
|
d259055af0 | ||
|
7ada2f864c | ||
|
587ebd5d47 | ||
|
fae26ee5da | ||
|
c4eca4469f | ||
|
d91cc96cd2 | ||
|
0b226c1868 | ||
|
359f61e55a | ||
|
16e049b7fa | ||
|
4fbc5a9558 | ||
|
8a6eec925f | ||
|
f365995c8a | ||
|
20ded56c99 | ||
|
4583e070df | ||
|
d4be1f3666 | ||
|
06d4b3281b | ||
|
1dcd5471a0 | ||
|
d0b6ef877e | ||
|
1e63b956f5 | ||
|
7734bdfdab | ||
|
7eb9036cbb | ||
|
6b2526ddbd | ||
|
0b1a898c7c | ||
|
fe247a60ef | ||
|
17402848f2 | ||
|
e6b4c2e700 | ||
|
e7c48d5870 | ||
|
781342be40 | ||
|
73b26407f6 | ||
|
b1d691178e | ||
|
dc189e1d58 | ||
|
95db4df13a | ||
|
34cf044a7c | ||
|
45f2198972 | ||
|
4c5535d1cc | ||
|
9dd16d3df5 | ||
|
21b92455af | ||
|
5a769fb51b | ||
|
e3e93df187 | ||
|
a17dc3cb52 | ||
|
02f6d4bd11 | ||
|
c63cab336c | ||
|
3ba39d5158 | ||
|
e85ab067bd | ||
|
8370a55263 | ||
|
e08a94fe1c | ||
|
e9364f4c3a | ||
|
5660d1e48e | ||
|
ac17020cd0 | ||
|
fdc58f952e | ||
|
765448fdf4 | ||
|
1e4864d8c5 | ||
|
dadd397bf0 | ||
|
6a2d31a481 | ||
|
136242e38c | ||
|
8bfcdb9266 | ||
|
e3c2f81506 | ||
|
af03003305 | ||
|
a8648b7cdc | ||
|
e8bacd84ce | ||
|
bcbf810cbe | ||
|
f0df8264fa | ||
|
e6b86b662a | ||
|
18e2c2f6dd | ||
|
15bf6222f5 | ||
|
b32f40c0fe | ||
|
53c23dfb6f | ||
|
c6d04d874f | ||
|
02cb6a6af7 | ||
|
9f1cc638c9 | ||
|
f395688c2d | ||
|
2e76b1f834 | ||
|
29fb83e98b | ||
|
156a88a3a3 | ||
|
c77a3674b0 | ||
|
db1349b95c | ||
|
e0d18c621b | ||
|
56d00fd0c8 | ||
|
457f63cce0 | ||
|
3dd6418160 | ||
|
1caed79895 | ||
|
7df224f382 | ||
|
e89c007a38 | ||
|
2174ee18dc | ||
|
8dbca0fa0b | ||
|
fccbaa0fbc | ||
|
089c942233 | ||
|
e768bea298 | ||
|
d9812f0d48 | ||
|
f80cc1a247 | ||
|
6906ee0e48 | ||
|
d292f2b9b4 | ||
|
6dadd467ab | ||
|
b1b7c3f7c1 | ||
|
5d14afad92 | ||
|
ad467029c7 | ||
|
adfca851fe | ||
|
c1bcabbc9d | ||
|
d070fd40a3 | ||
|
0221112879 | ||
|
bcacc27456 | ||
|
a24db20c64 | ||
|
5fb9a24f22 | ||
|
d28c32624c | ||
|
2cbbf7d9a6 | ||
|
b18b497a81 | ||
|
2fa6370dc0 | ||
|
e92d9317aa | ||
|
9eb3d84715 | ||
|
c0f11c27a3 | ||
|
932d66b0ee | ||
|
aece6cc327 | ||
|
5685ba7f55 | ||
|
d121e4c9b5 | ||
|
904c82be47 | ||
|
1b913b8088 | ||
|
6d212ea24e | ||
|
3eed5de367 | ||
|
970d28bce9 | ||
|
2080b9a87c | ||
|
cabaf37437 | ||
|
94916ebbd1 | ||
|
50a46933f6 | ||
|
85aa32338e | ||
|
ba7ca84899 | ||
|
2d9c9707e3 | ||
|
d507953c70 | ||
|
d855f70e3b | ||
|
a2a049c5cc | ||
|
58f66e54f9 | ||
|
ba856dac4e | ||
|
a01036760e | ||
|
0af913cc9a | ||
|
2e3aec3184 | ||
|
1cea791245 | ||
|
eae4618c52 | ||
|
e6d1daacee | ||
|
e71709f0ec | ||
|
8af6ffdb49 | ||
|
d2289fa542 | ||
|
1ae1391cb9 | ||
|
6aa07243cd | ||
|
5d9c986f87 | ||
|
c7e9096dfd | ||
|
13d83d86f6 | ||
|
19a09b93dd | ||
|
590b3d0fd4 | ||
|
ff31efdbf7 | ||
|
c67698b34e | ||
|
88cacbc898 | ||
|
3eaa005c7e | ||
|
834a1ed608 | ||
|
0c178d858f | ||
|
6d17ad4da6 | ||
|
f311198da0 | ||
|
bd2b72235e | ||
|
11f42761aa | ||
|
47a9dda3b8 | ||
|
d259e4512b | ||
|
d530fd31b0 | ||
|
662a30ffaf | ||
|
56031b2e1a | ||
|
57e1709782 | ||
|
2c210e4b58 | ||
|
6ef1dd56f5 | ||
|
a4c88a8591 | ||
|
4afc472068 | ||
|
e27cee53a8 | ||
|
1a478bd78a | ||
|
4e1b865775 | ||
|
02e392e215 | ||
|
70ebf2f5d8 | ||
|
c21ea6b8da | ||
|
da401cafdf | ||
|
e89b258970 | ||
|
b1a777a95a | ||
|
21d3f15059 | ||
|
9651072103 | ||
|
2475e8c0c4 | ||
|
11fe48f2d2 | ||
|
ee7bee2766 | ||
|
0582c39d33 | ||
|
f176233f0a | ||
|
610e9239a4 | ||
|
98728d37a6 | ||
|
d7cf05e693 | ||
|
75d3ea34fc | ||
|
66f9e06c25 | ||
|
f52f60307b | ||
|
420bdedcb5 | ||
|
0c1a605693 | ||
|
393181df20 | ||
|
315d59d615 | ||
|
af5c63f805 | ||
|
ba9dae10c3 | ||
|
e4347e5520 | ||
|
2ea8af83bd | ||
|
bbdc036c3e | ||
|
344e43a94a | ||
|
f6cf23a8c2 | ||
|
2db488b7a4 | ||
|
cee14afc03 | ||
|
a7b6652fba | ||
|
e140a2980b | ||
|
29311c7eb8 | ||
|
059fbe7958 | ||
|
79f3e30fb6 | ||
|
f42bc3aaae | ||
|
09dd647741 | ||
|
c33ba541b0 | ||
|
1d3f431628 | ||
|
3a05855f71 | ||
|
eb66a2f32f | ||
|
3c1860cca2 | ||
|
356bca119d | ||
|
1a21266325 | ||
|
d722b7255c | ||
|
647017d18c | ||
|
b1698bc0d5 | ||
|
b8ce687ec2 | ||
|
2f68bbd27a | ||
|
419e83f6d8 | ||
|
eb5390b94d | ||
|
8e026bf95d | ||
|
c4b870bfd3 | ||
|
618586c577 | ||
|
acc046def6 | ||
|
da1003ac41 | ||
|
7555f209b6 | ||
|
b3377fe5fb | ||
|
74834b2d88 | ||
|
56dfb2c734 | ||
|
8e0b2b752c | ||
|
c01bdd860a | ||
|
2611f72f5d | ||
|
1be455e0e0 | ||
|
2e54967a6d | ||
|
6c5dfd0bbc | ||
|
69530a5c94 | ||
|
b640efa209 | ||
|
5c2d7b8fa5 | ||
|
688da5389c | ||
|
377ae75e60 | ||
|
9bbd59438e | ||
|
dd4f1a0d0f | ||
|
40ee39f258 | ||
|
44ca43c7ee | ||
|
3536ba43f5 | ||
|
15e5851383 | ||
|
2b3a6e5361 | ||
|
aa8f98392d | ||
|
bde92b34dd | ||
|
650c92a3cf | ||
|
457cb7ace0 | ||
|
3e8fe57fc1 | ||
|
90bbe462ff | ||
|
72d546d6c2 | ||
|
dd08a6505e | ||
|
47bcb214d1 | ||
|
a16ef5b7ff | ||
|
300445948e | ||
|
8324360045 | ||
|
2d0ccf84f9 | ||
|
ebd2034564 | ||
|
5852917a10 | ||
|
a361c01ed6 | ||
|
379a8f2f86 | ||
|
d8bb8f1efb | ||
|
db61f8a0fa | ||
|
e261a159d5 | ||
|
337335bfad | ||
|
ed907da190 | ||
|
3ea4c3b8bf | ||
|
afeab659e1 | ||
|
130b6559a6 | ||
|
97c55ae6f1 | ||
|
67dc870e52 | ||
|
2f38731f62 | ||
|
745a05d984 | ||
|
7f7db4efb6 | ||
|
da81efe9c1 | ||
|
99122fcb78 | ||
|
dcd7830a35 | ||
|
9f284c0582 | ||
|
9616d68e03 | ||
|
cb97085e48 | ||
|
7eba111704 | ||
|
3cc5a29c1b | ||
|
2fa0f283ea | ||
|
7e2e3c4780 | ||
|
4c59bae1d2 | ||
|
675c467e12 | ||
|
130e7317bc | ||
|
bb56610093 | ||
|
bd5892f2a6 | ||
|
06e83340e8 | ||
|
7508a2b383 | ||
|
f1e4229b23 | ||
|
c9a936f375 | ||
|
ce4a62574a | ||
|
e750f8f457 | ||
|
ded34561b1 | ||
|
e0a221ba1f | ||
|
c5453835c2 | ||
|
0459596e97 | ||
|
6ea59ffa94 | ||
|
aab939cf6c | ||
|
fe2402b611 | ||
|
029dbe7d94 | ||
|
af6434a533 | ||
|
dee4b33c64 | ||
|
8fff0075ba | ||
|
d7caaceb64 | ||
|
3889482f0e | ||
|
1dc496a2dd | ||
|
056e6eae82 | ||
|
06e876aee0 | ||
|
713689491b | ||
|
17ab45da43 | ||
|
2a1df2063d | ||
|
d88487e30b | ||
|
8884465262 | ||
|
a85ccb94e3 | ||
|
391de22342 | ||
|
0592a39164 | ||
|
dca287748d | ||
|
021878e942 | ||
|
0f2525d476 | ||
|
4d804649fc | ||
|
7209b3c7d3 | ||
|
6f88b6e64e | ||
|
4bcde36a97 | ||
|
7f4fc4d371 | ||
|
513361ef0f | ||
|
8ce236de80 | ||
|
8b8083a639 | ||
|
26ac8e35cb | ||
|
20600123f8 | ||
|
b3d6f8861f | ||
|
5405279273 | ||
|
634582eab7 | ||
|
2c48f9aa4c | ||
|
8d0dda6523 | ||
|
6967c70580 | ||
|
7bab3579ec | ||
|
aa8c4a6eb7 | ||
|
99a50fe874 | ||
|
65b48aa903 | ||
|
af62e8267f | ||
|
45ab6e9b06 | ||
|
a7a219b99b | ||
|
c2d5696b5b | ||
|
2ef37f01b1 | ||
|
84def0c041 | ||
|
26ede9a679 | ||
|
c0ee12ca41 | ||
|
926ffe536c | ||
|
2b2f5d6693 | ||
|
d4f0aaa089 | ||
|
5b434aae6e | ||
|
1ffd797e0a | ||
|
8acc027f38 | ||
|
3139a7e431 | ||
|
e7cb646a58 | ||
|
ec9f50317f | ||
|
fd0c63fe52 | ||
|
31aef86c0f | ||
|
943b96e7a1 | ||
|
74b78307ee | ||
|
c0492d4af4 | ||
|
f5b754a382 | ||
|
cee695da28 | ||
|
2ef1c96325 | ||
|
d3badb88ef | ||
|
1f80b803f7 | ||
|
2ea41c90b5 | ||
|
3fa24f87c0 | ||
|
bfe19e82ff | ||
|
5108e1a1cd | ||
|
5e1b4b2d23 | ||
|
03a6eb26be | ||
|
0a11acf7ae | ||
|
ab29718a45 | ||
|
7e7a6e4937 | ||
|
c53c2d7e64 | ||
|
6e38cf878e | ||
|
066503b838 | ||
|
3e70342265 | ||
|
17994ff245 | ||
|
cbd884d54a | ||
|
b8c3a44d81 | ||
|
ce28d8a92c | ||
|
457e66527a | ||
|
444560543c | ||
|
b9bd8f6b34 | ||
|
cd3059aa14 | ||
|
741add0666 | ||
|
ee59303d3c | ||
|
20639b0f02 | ||
|
ea7b2ecec0 | ||
|
09989e6184 | ||
|
883e33e72a | ||
|
ed2d321746 | ||
|
b50d8fca16 | ||
|
1c7c6d6592 | ||
|
5cf89bf2bb | ||
|
49b07b3749 | ||
|
0b95cf1251 | ||
|
a3f42e36ac | ||
|
973e43ae6a | ||
|
6b75c86a17 | ||
|
e80e189e6b | ||
|
27dc2e1b9d | ||
|
edb7c76caa | ||
|
7859d31ca0 | ||
|
6c640d2abe | ||
|
61ee3a9412 | ||
|
4ed18495f3 | ||
|
5c8b2cde92 | ||
|
5c2073481d | ||
|
84c204a7b3 | ||
|
6c15f251c6 | ||
|
48fcf58eb9 | ||
|
3c13f4b4cc | ||
|
a14826d75e | ||
|
f86bd3dfee | ||
|
069b7a45ed | ||
|
e3e48ff9b7 | ||
|
33814d1180 | ||
|
f126a6024e | ||
|
b6d45a5a07 | ||
|
f6c681eb5d | ||
|
c4cc158a77 | ||
|
e58cf00a96 | ||
|
6976a66758 | ||
|
6b1fc00910 | ||
|
8168b8fce4 | ||
|
1e6b6fef7e | ||
|
73f04e3ede | ||
|
9f469c08d1 | ||
|
051a28b55a | ||
|
ff449e7741 | ||
|
8d239d368b | ||
|
3a5309e9a0 | ||
|
86ef7bab28 | ||
|
f9928a5843 | ||
|
2c99f060f0 | ||
|
543f986955 | ||
|
b68c90d59a | ||
|
66c6cd2a10 | ||
|
f5f8c44ca6 | ||
|
58056c49f7 | ||
|
af0a6d2820 | ||
|
f3e2c51774 | ||
|
053e38db38 | ||
|
ba81a68982 | ||
|
f8c94fd83f | ||
|
9777ed2e62 | ||
|
aba23eb513 | ||
|
0eda451c24 | ||
|
8f38b7191a | ||
|
ff3cabbf3a | ||
|
dfcfe78732 | ||
|
ff20131af1 | ||
|
ccbc300b68 | ||
|
84dcfb6ddc | ||
|
1db68327f9 | ||
|
7752789c3a | ||
|
54c15e7e0a | ||
|
0092796fd2 | ||
|
187a38c91f | ||
|
b025942a14 | ||
|
0e515b2e1f | ||
|
a341bfd8ca | ||
|
f80acdada0 | ||
|
cf049a07c2 | ||
|
0ca0836e83 | ||
|
60b0f0dc53 | ||
|
c3921f2112 | ||
|
aa619c5594 | ||
|
0677a256ec | ||
|
97ffbf5aad | ||
|
006b2da14e | ||
|
56b4ddc6b4 | ||
|
2c0c0b9e21 | ||
|
9e312f2063 | ||
|
bbeecb40ae | ||
|
48c9361c01 | ||
|
d686b877b1 | ||
|
d2d01b337d | ||
|
b0bfe71b9b | ||
|
38f3fa0210 | ||
|
86ae70780c | ||
|
65e16b4814 | ||
|
70966c2b63 | ||
|
ba7f36328d | ||
|
511ecf98d5 | ||
|
b5831344a0 | ||
|
984eba809c | ||
|
f778033bd8 | ||
|
a8f2204f4f | ||
|
4c56cbe8c8 | ||
|
71d35a03e1 | ||
|
c8fd48523f | ||
|
fbd3bf7a98 | ||
|
a0356f587e | ||
|
199a4b725b | ||
|
505df84783 | ||
|
baa9473383 | ||
|
ba5d23290a | ||
|
adda02b6b1 | ||
|
1f59bd9f92 | ||
|
b61678d39c | ||
|
b23297bb7e | ||
|
f56c38d69b | ||
|
c2b24dd355 | ||
|
c4c8e74a8a | ||
|
c4029300c2 | ||
|
52320844fc | ||
|
b4e20409de | ||
|
4ecc6555bf | ||
|
892c32c8b7 | ||
|
bad305dcbf | ||
|
7266a16295 | ||
|
416a2de179 | ||
|
349ea35dc3 | ||
|
0fb1fbf0d1 | ||
|
643fd34478 | ||
|
186c9aa33b | ||
|
af51241c0d | ||
|
36ec1b33fe | ||
|
eaee8d5b78 | ||
|
84a0a28be2 | ||
|
ac19ee3e2e | ||
|
438af042ed | ||
|
122f11c790 | ||
|
638434c103 | ||
|
3a44098ddf | ||
|
1e1c3506fe | ||
|
b557e9e826 | ||
|
da0d1b71ce | ||
|
4d96ed4c68 | ||
|
1bc63a61be | ||
|
5c35ccb9ca | ||
|
a1ecefee21 | ||
|
b5d7eba4f6 | ||
|
4b111008df | ||
|
fb5afff9d5 | ||
|
de99dfef4e | ||
|
bcdc3563a5 | ||
|
9ef0a1f0a2 | ||
|
d0629d4e66 | ||
|
65e98eab9c | ||
|
a0d9764443 | ||
|
8293f270df | ||
|
38a1c97a51 | ||
|
b26e4d672f | ||
|
daa5268cf2 | ||
|
9da3f98c23 | ||
|
8fd691be69 | ||
|
7fc0e36b2f | ||
|
482bed522f | ||
|
7788685340 | ||
|
af1af6f391 | ||
|
d5c2e6ec35 | ||
|
d8382c6de2 | ||
|
c4cfff4b3f | ||
|
cfe0c95c97 | ||
|
50c1bf8bb0 | ||
|
cc3d059783 | ||
|
4aa86a574f | ||
|
3a8039cbc0 | ||
|
e4f9f6447f | ||
|
14482ff6da | ||
|
116090bff1 | ||
|
6082220f7f | ||
|
74fd16b953 | ||
|
82cffcbc23 | ||
|
4e1a77326e | ||
|
54cf52069e | ||
|
be8f14167f | ||
|
70b811096c | ||
|
1efd267ee6 | ||
|
31267b4095 | ||
|
4982e1cbcf | ||
|
be3b16b7fa | ||
|
393a0ac0df | ||
|
a0bbcb0401 | ||
|
3f65bc78e8 | ||
|
d005440544 | ||
|
94d2da1685 | ||
|
4c5ba0617a | ||
|
a58bf149fc | ||
|
005be4e8ba | ||
|
b81d7a0ed8 | ||
|
9a690ed421 | ||
|
009989d7ae | ||
|
c7d1ad27f0 | ||
|
27032c1780 | ||
|
61a722218a | ||
|
3137c27e56 | ||
|
7b35c3036e | ||
|
8e03f3a045 | ||
|
8f26cff65a | ||
|
00533bae4b | ||
|
8255728f53 | ||
|
470335e27a | ||
|
56887747a6 | ||
|
1dcae0c0a6 | ||
|
8759a6a14d | ||
|
5d072d1030 | ||
|
78517f75e8 | ||
|
42ed7fbb0d | ||
|
96be3e2505 | ||
|
2fa3b9070c | ||
|
d827c53a85 | ||
|
436ac72b82 | ||
|
7c15075231 | ||
|
8e3ad2d1f3 | ||
|
733bbf9cd1 | ||
|
822660732b | ||
|
d6bd4312ab | ||
|
491bde181c | ||
|
fdce524811 | ||
|
cf10549df4 | ||
|
fd01e22ca4 | ||
|
334359bb0a | ||
|
eda1656e75 | ||
|
6cea6be4a7 | ||
|
6ecc5c19a2 | ||
|
c321bd70e1 | ||
|
851600630c | ||
|
e3896d1f60 | ||
|
c71cf272c8 | ||
|
d12c6f89d2 | ||
|
5965d8d503 | ||
|
94f458ff98 | ||
|
c07a9e9d59 | ||
|
b9db9eeab2 | ||
|
f34b449f61 | ||
|
fc24843274 | ||
|
22b6239304 | ||
|
aa8fe99113 | ||
|
7c223db1d5 | ||
|
0c18b2e7ff | ||
|
d68ee8dcea | ||
|
671aaa7e95 | ||
|
faefe624f6 | ||
|
f93259a2f1 | ||
|
606524f9e7 | ||
|
cd89db9bb6 | ||
|
f760c13e8f | ||
|
687cd32142 | ||
|
fb27297df9 | ||
|
3e350bdc90 | ||
|
0b14f0a379 | ||
|
3206979488 | ||
|
4c27bfbf7f | ||
|
7c4fd9473c | ||
|
3af11fb2b1 | ||
|
c839cc1f15 | ||
|
a0f2e2ebdd | ||
|
d07e62b2f1 | ||
|
e7f957def2 | ||
|
16ab57c9a6 | ||
|
1a67052cbd | ||
|
f85a802ebd | ||
|
3b5c08ecf8 | ||
|
450c63ad28 | ||
|
a8f472f44e | ||
|
fa3a301e97 | ||
|
b1ef1be9a3 | ||
|
62ef951ace | ||
|
06660f9170 | ||
|
7662ca8a96 | ||
|
e04fc74fcf | ||
|
f9bca7619c | ||
|
1b9aa727f8 | ||
|
d54c1935f8 | ||
|
9cfad05793 | ||
|
03ab471d23 | ||
|
b2b69e40fd | ||
|
c6ff445dd4 | ||
|
0948a94409 | ||
|
9be20d6130 | ||
|
c4e484539d | ||
|
234f32265e | ||
|
633c904852 | ||
|
5300eddf33 | ||
|
9f558d13e6 | ||
|
9ae59e5ea0 | ||
|
1b1c1c2a55 | ||
|
df4bd721b5 | ||
|
baa876d4d9 | ||
|
b99dceab74 | ||
|
114e254aa6 | ||
|
fbfd8c48aa | ||
|
d40e3145fe | ||
|
f4a16c8dc9 | ||
|
2ce6bd2378 | ||
|
9334099bed | ||
|
077edb08f6 | ||
|
72d5146a3e | ||
|
fa14321aa1 | ||
|
8f679fcbf3 | ||
|
78cf7dc873 | ||
|
9fff3a13a5 | ||
|
99f43400bf | ||
|
77b464f2bd | ||
|
07e251d488 | ||
|
659d135fca | ||
|
24414369d7 | ||
|
92c1fb77e9 | ||
|
ae1f53775f | ||
|
bd6b5568eb | ||
|
5f2964d3e8 | ||
|
c6865d0862 | ||
|
ef8fc3913e | ||
|
56667ec2bc | ||
|
fa21613951 | ||
|
f735d12a66 | ||
|
2f7a396778 | ||
|
12336f5c15 | ||
|
1661304f10 | ||
|
68162e1a27 | ||
|
95a25c72dc | ||
|
30772da0e1 | ||
|
ef84a8869e | ||
|
d3879a36d1 | ||
|
93afc9458a | ||
|
5cd8e4ab7e | ||
|
994c2ebca1 | ||
|
81f5068354 | ||
|
3e60d7aa11 | ||
|
30aa3a26ad | ||
|
9da5dd0090 | ||
|
65f007ace7 | ||
|
2a8feda691 | ||
|
36b7e8569e | ||
|
221f961574 | ||
|
7210cc1da6 | ||
|
5fa23b1785 | ||
|
2cab9f7fe9 | ||
|
3bfcb1ebdd | ||
|
c1eb5f8b74 | ||
|
582b7eab66 | ||
|
26281662b5 | ||
|
ac39bf991f | ||
|
0a9e20615e | ||
|
8cafa1bcdf | ||
|
66ddf44399 | ||
|
933ae143b3 | ||
|
8c2e63807c | ||
|
460363c4ba | ||
|
29a17edaa5 | ||
|
ed161d3d49 | ||
|
7868ffac35 | ||
|
411b014da2 | ||
|
3a8aa4200d | ||
|
dd8471e786 | ||
|
f33b4b0dc0 | ||
|
8ab8f7a740 | ||
|
ee9e3fe27b | ||
|
d4830caac0 | ||
|
3b4e3b1370 | ||
|
533c8ca31c | ||
|
8668af17f6 | ||
|
5b866e071c | ||
|
37af180edc | ||
|
0d5dc01048 | ||
|
bd2be0a763 | ||
|
98cbd7d8da | ||
|
26f3305743 | ||
|
3c0480596d | ||
|
81d2231e6f | ||
|
2d041a1fa9 | ||
|
910fb0930e | ||
|
cb742a677c | ||
|
28c24e5fef | ||
|
50577883dc | ||
|
20f9b9e412 | ||
|
1d05a917f9 | ||
|
240bd6c3bf | ||
|
c01bb44757 | ||
|
5e93394ae7 | ||
|
a8b55a16fd | ||
|
d7fb245213 | ||
|
6467c8d611 | ||
|
c47b37af4f | ||
|
a5bacf5652 | ||
|
6589216ed3 | ||
|
b6dc410464 | ||
|
928ff7c78c | ||
|
c9335598db | ||
|
32babd3958 | ||
|
7f405686d1 | ||
|
5bd736029f | ||
|
397198c6d0 | ||
|
54188b4128 | ||
|
f3da9de744 | ||
|
aeb95c4509 | ||
|
f394dfb8d0 | ||
|
6781a76de2 | ||
|
69a9aa4594 | ||
|
afa02dcce9 | ||
|
febb382030 | ||
|
1906155c18 | ||
|
ffabd5d7db | ||
|
9e2360791d | ||
|
19cbc1b258 | ||
|
df2ea1e875 | ||
|
74fa30e59d | ||
|
6833af6286 | ||
|
4940968cd5 | ||
|
a9975071c3 | ||
|
cc4340b80c | ||
|
252f05e0f7 | ||
|
f5e0382123 | ||
|
600c6a0dcb | ||
|
df60e59a95 | ||
|
cf90e77e57 | ||
|
3e0bd44d2a | ||
|
7bb93d4f3e | ||
|
4dfc11a140 | ||
|
7eeebf198b | ||
|
175ffe29f6 | ||
|
ff9937f942 | ||
|
ef452427e3 | ||
|
a04970bd54 | ||
|
03a02fa565 | ||
|
b2f27a4519 | ||
|
b906a1b521 | ||
|
754e4255b6 | ||
|
ff39f09c4e | ||
|
3078b47d06 | ||
|
71de50dae8 | ||
|
e8b722f7b2 | ||
|
a2053d073f | ||
|
aa72b08c16 | ||
|
66480da218 | ||
|
3b214f6610 | ||
|
149aebb0bc | ||
|
c36fc70ab4 | ||
|
681fe3485d | ||
|
34680becaa | ||
|
354f4491c8 | ||
|
c4fd1cfc8f | ||
|
a4e9e4b23b | ||
|
eac7794741 | ||
|
1cb9690001 | ||
|
1101e7ef64 | ||
|
3b6128d590 | ||
|
7f4fca63ed | ||
|
4b59ef4733 | ||
|
3d39f6ce88 | ||
|
5f810d908f | ||
|
c7cfd56b72 | ||
|
ada6b7875c | ||
|
2b20b2a80b | ||
|
5825e8fee8 | ||
|
70488ffd15 | ||
|
2900fa733d | ||
|
7d61dd13d9 | ||
|
af8131e68f | ||
|
c049129147 | ||
|
1e035064f4 | ||
|
2dce876a86 | ||
|
2856525c12 | ||
|
22cfb7059a | ||
|
1650cee16c | ||
|
25cdd737a9 | ||
|
9153d16a6d | ||
|
03ead27f6c | ||
|
edad766fd3 | ||
|
9bcc31a9fe | ||
|
7652c35ee6 | ||
|
dd52f4c84a | ||
|
45bb2cdd82 | ||
|
a4bfb0e92c | ||
|
26006f8036 | ||
|
ef4caa951c | ||
|
5824d06fd7 | ||
|
57a73d1b1b | ||
|
731aaaafe2 | ||
|
bdd3aa8e39 | ||
|
99335a07e5 | ||
|
9d633f2087 | ||
|
174f22aa2f | ||
|
e39b3796f3 | ||
|
11370979e5 | ||
|
0afae45bc5 | ||
|
f8ac952cd7 | ||
|
c4e5d67551 | ||
|
cff4e46694 | ||
|
38ef216894 | ||
|
1a2d013c97 | ||
|
cffa8b4feb | ||
|
fce2e21c9f | ||
|
a0ffa69b49 | ||
|
a0089685dd | ||
|
633ff0ea42 | ||
|
163795e73a | ||
|
45eebf3285 | ||
|
14eec2e57a | ||
|
274d98f4d7 | ||
|
51a5a78eb5 | ||
|
d4ae592a85 | ||
|
8ff8ed7f76 | ||
|
18b49a6f62 | ||
|
35d318818a | ||
|
0a94242337 | ||
|
d1681fac72 | ||
|
8504a16e83 | ||
|
41e66edd14 | ||
|
10b3119b4a | ||
|
c772c4a2d5 | ||
|
e9830f0835 | ||
|
bcc66c9a86 | ||
|
1f3c99dff3 | ||
|
b085ac9296 | ||
|
1add00a68d | ||
|
f9bf7f7e05 | ||
|
a63c5e6725 | ||
|
4108b7ada6 | ||
|
42388450e1 | ||
|
e720a14dc4 | ||
|
9d3895d69a | ||
|
16dd6b1712 | ||
|
e447d83024 | ||
|
8fee1975b4 | ||
|
3533ac163c | ||
|
1b304e60d9 | ||
|
5bd17c9198 | ||
|
136f0e423e | ||
|
e84d9e21f7 | ||
|
fa084143ef | ||
|
ca17c70109 | ||
|
5818e2c2d4 | ||
|
467749eb57 | ||
|
dd0c353afb | ||
|
9e762fa222 | ||
|
ea04269c49 | ||
|
e2d84f9a58 | ||
|
52b6f00363 | ||
|
55c42fde88 | ||
|
0dc1eb8757 | ||
|
1936aeccb9 | ||
|
c1c158c0aa | ||
|
bcfc7ea481 | ||
|
de8bbaadd1 | ||
|
318259689f | ||
|
f802611359 | ||
|
53479b5924 | ||
|
9cae786f40 | ||
|
48292beec8 | ||
|
a45ba51f89 | ||
|
9119884e53 | ||
|
37e2839fa3 | ||
|
6b0428774d | ||
|
0d2f22838a | ||
|
4bc19876ca | ||
|
902d76da36 | ||
|
d8161c431f | ||
|
68d6f1c1aa | ||
|
ef1d53c207 | ||
|
823b62d8ab | ||
|
dece7e0f9c | ||
|
68cdf8877c | ||
|
831a1d7ad1 | ||
|
715f4bd2c3 | ||
|
74a12bb802 | ||
|
51fd8e1288 | ||
|
2fe19c04b9 | ||
|
37019d33fd | ||
|
0fe939cd7c | ||
|
b960ebeb8b | ||
|
7334fb0125 | ||
|
d8fe3c5377 | ||
|
76182c246d | ||
|
b9aaba0432 | ||
|
156948c496 | ||
|
547dbf77aa | ||
|
a68cd712c6 | ||
|
9e7aeed848 | ||
|
95fa123a0b | ||
|
657ff58500 | ||
|
ff029e5efc | ||
|
f4528b288f | ||
|
1aa0dbdaf5 | ||
|
743df84569 | ||
|
16231da5ef | ||
|
7b71f024fb | ||
|
0a05cdc381 | ||
|
106559371c | ||
|
cafd953f87 | ||
|
7ddd755acc | ||
|
302ffe5e56 | ||
|
65216df3a5 | ||
|
76ebb0df08 | ||
|
0591b5e47b | ||
|
bb6f9ec844 | ||
|
592f60643a | ||
|
3035588dfa | ||
|
6e727a49bf | ||
|
0dfe12840d | ||
|
d915fee833 | ||
|
9ea41b4d26 | ||
|
8bc9fd23bb | ||
|
18212052a4 | ||
|
3304e27fa3 | ||
|
be206156b0 | ||
|
0628f96713 | ||
|
41b129e990 | ||
|
ebc49d938a | ||
|
58b7711bdd | ||
|
909dfcc436 | ||
|
70fc8fa2eb | ||
|
242aae514e | ||
|
d94b1e6e8a | ||
|
d18e81f932 | ||
|
d3293336b1 | ||
|
1eeb3bdcdf | ||
|
36bfd7b9ce | ||
|
f84a04e113 | ||
|
516f3295bf | ||
|
2d5289e7dd | ||
|
18efd84a35 | ||
|
b34c90b189 | ||
|
a45c1a3914 | ||
|
1bdf9d657e | ||
|
b294a92ad2 | ||
|
2db362ab3d | ||
|
5f275a6b9c | ||
|
fa914b2811 | ||
|
a128e2e4fc | ||
|
03c7f2cf5b | ||
|
102528e5d3 | ||
|
8f4af4f7c2 | ||
|
667af10017 | ||
|
e5a64a1e0a | ||
|
236fa8e238 | ||
|
70a58a0bb0 | ||
|
769c7f1ea3 | ||
|
5a8045d1fb | ||
|
5a73b636e3 | ||
|
524e09b45e | ||
|
1f46670266 | ||
|
a857f603c8 | ||
|
b7d8f3d005 | ||
|
129035967b | ||
|
45b44f8a59 | ||
|
e80dc52175 | ||
|
22bb3e5477 | ||
|
f89e8e6ceb | ||
|
157a61845b | ||
|
0fcdc3c200 | ||
|
d1f09ecd0c | ||
|
3484ab3c0c | ||
|
80df582ebd | ||
|
dc967e2ef2 | ||
|
e2c1a38d87 | ||
|
c9e7c76ee5 | ||
|
5550b1a74e | ||
|
51b520db0c | ||
|
f06c21c8cc | ||
|
fcf0bef2cd | ||
|
7c8e00e5e0 | ||
|
ce72157bf7 | ||
|
31f5539311 | ||
|
b63fb9f17f | ||
|
9b3718edfb | ||
|
156e39ebb2 | ||
|
c506188c13 | ||
|
b64c21cce6 | ||
|
e85755fbda | ||
|
3e3d27f48d | ||
|
32f75597a9 | ||
|
d7d35f74f2 | ||
|
5dc03752ca | ||
|
b26446bd88 | ||
|
9e13184256 | ||
|
b7170c78a5 | ||
|
e26d363b5e | ||
|
7ae8f4c9d0 | ||
|
664e0258bf | ||
|
8023cbcc38 | ||
|
22c322fc37 | ||
|
2bb4a8747c | ||
|
098a006f32 | ||
|
d47a296d7a | ||
|
c2ce71a38c | ||
|
a7c6abc54e | ||
|
79ba315008 | ||
|
26e87509be | ||
|
af2fec89d8 | ||
|
61cee043e6 | ||
|
fd57931cc9 | ||
|
44b6bca89a | ||
|
0bd9386df2 | ||
|
611723e44b | ||
|
f8e65c1161 | ||
|
ab064a7f36 | ||
|
4e94ce0cc7 | ||
|
7c6e3fe9c4 | ||
|
7579ebc02a | ||
|
61ac4c7af7 | ||
|
2533bde27a | ||
|
fc1ed7d7cb | ||
|
281a9f042b | ||
|
1d35c745bb | ||
|
51dba1eec3 | ||
|
6e5e96b047 | ||
|
e13f8996f2 | ||
|
7887bcba89 | ||
|
3a92899081 | ||
|
5d64155bb6 | ||
|
6f66f37fc7 | ||
|
890c6e97fd | ||
|
404a7bab18 | ||
|
2337c3ff69 | ||
|
4a6f833fca | ||
|
c541cb5cba | ||
|
df82567356 | ||
|
1bc0ec201a | ||
|
403db6277f | ||
|
4e3bd55c73 | ||
|
ab6d0e3277 | ||
|
480e748b04 | ||
|
b541d214ed | ||
|
0c8ed18ca5 | ||
|
61114d8328 | ||
|
9b9e98a26e | ||
|
60f9fbf800 | ||
|
2ff326b563 | ||
|
266cd623a5 | ||
|
ad362b1d4c | ||
|
47beddc6c6 | ||
|
913e5404da | ||
|
67bc568db6 | ||
|
5f53d3f917 | ||
|
e9798cd1b4 | ||
|
4ef55e5088 | ||
|
9399a54c7a | ||
|
d86b816491 | ||
|
88b95c1236 | ||
|
e56c235424 | ||
|
ec256166cc | ||
|
9de90ca7d5 | ||
|
3e53cc175f | ||
|
b21b300625 | ||
|
52c0a09107 | ||
|
8d97fafb2d | ||
|
fa5f47127c | ||
|
316a57864a | ||
|
a287c8259d | ||
|
c276cfc371 | ||
|
f33328308c | ||
|
1d1a6ee52f | ||
|
d248bf596a | ||
|
ce82c79ff9 | ||
|
d327ec904c | ||
|
b74aced6f3 | ||
|
a1e3e7f24f | ||
|
15976b8207 | ||
|
b1d9e5580c | ||
|
3dc83ef19d | ||
|
14775c822f | ||
|
69a5605551 | ||
|
c2dc4ef215 | ||
|
e6eedc0717 | ||
|
d901cb04b8 | ||
|
f66b539027 | ||
|
d961e20b15 | ||
|
93f791e5d0 | ||
|
db92f29c00 | ||
|
be255613de | ||
|
98a007cb2f | ||
|
b4648136c5 | ||
|
d3deaa6a82 | ||
|
e81aa1cdb2 | ||
|
24f0c88123 | ||
|
b31c6012ae | ||
|
d99f1631ca | ||
|
8260264416 | ||
|
097162eceb | ||
|
d8cbb3540f | ||
|
0f90a3cf60 | ||
|
108a54a4a8 | ||
|
fc767ee562 | ||
|
566c00ef12 | ||
|
407e4f6ca2 | ||
|
254aa8c9ea | ||
|
b4afca3e7e | ||
|
20f7af25e9 | ||
|
69652ca2ca | ||
|
89728f41e1 | ||
|
9283d766d3 | ||
|
bcd92b43ce | ||
|
de82f21446 | ||
|
984a534300 | ||
|
50f3c891fa | ||
|
e3ab30a2a5 | ||
|
f2d41bd99c | ||
|
b53ae884a6 | ||
|
f4997e46fb | ||
|
110ee9ff35 | ||
|
c76d68503a | ||
|
5470d14a11 | ||
|
02139fcca6 | ||
|
16e52f0427 | ||
|
96edaebdd3 | ||
|
8907b7e911 | ||
|
fd0f093e10 | ||
|
e88007af2d | ||
|
a24fdd1c2b | ||
|
f0af33bd2b | ||
|
057f31132b | ||
|
197e65c3a9 | ||
|
d9aa931fac | ||
|
2577fb804b | ||
|
bab930a456 | ||
|
511ec4ba8a | ||
|
013b91394e | ||
|
d9c98316fd | ||
|
88d79d35eb | ||
|
25d33e96cc | ||
|
1fdcbc3f15 | ||
|
05aeb3fbd1 | ||
|
50f9c1e5a4 | ||
|
02b26ac4e6 | ||
|
11d2258afc | ||
|
14c2ca85ec | ||
|
1010edf4bd | ||
|
9e8260736b | ||
|
06d1bbc20f | ||
|
135ebaafa0 | ||
|
ce2ffde22e | ||
|
7d5ddbf51c | ||
|
df58068e84 | ||
|
7d326ff076 | ||
|
49c59339d9 | ||
|
4ab3f1f41f | ||
|
e6c61f207d | ||
|
4e7e896601 | ||
|
55cf3b60eb | ||
|
1a628588b4 | ||
|
ba3872ff87 | ||
|
69843e9ac4 | ||
|
a4fb4e76cb | ||
|
489ceab4b5 | ||
|
1afed8ae15 | ||
|
10c27c3189 | ||
|
975363b660 | ||
|
c8797298ea | ||
|
565f271c5c | ||
|
0c5a3fab22 | ||
|
04b0760e27 | ||
|
e3287b93a5 | ||
|
c4fee124b3 | ||
|
ec0012209d | ||
|
59d72bb4ed | ||
|
3b2893f2f4 | ||
|
63d1cc10e2 | ||
|
d72d4286db | ||
|
23fb4b50c9 | ||
|
08a76133c2 | ||
|
08234efedf | ||
|
1bab373707 | ||
|
85a47ffb68 | ||
|
153eef16bb | ||
|
7efd8089c8 | ||
|
533442f33e | ||
|
a7bca9bcea | ||
|
6c01e4b99c | ||
|
7deb9bf30f | ||
|
1614e2c825 | ||
|
69700f068f | ||
|
91951ed734 | ||
|
24680b731f | ||
|
a8a7d01a84 | ||
|
9b11aaf1eb | ||
|
94516de724 | ||
|
a2027fc78c | ||
|
be5577c2f9 | ||
|
93dc08a05f | ||
|
def2ace4ec | ||
|
4f0261d739 | ||
|
6103811de8 | ||
|
fd904c65a7 | ||
|
04bf8482b2 | ||
|
f5fd5e0457 | ||
|
0de89b42aa | ||
|
e8914552b1 | ||
|
bfd302109e | ||
|
796ad47dd0 | ||
|
e9915463a9 | ||
|
59aecda8cf | ||
|
7d00ccbbbc | ||
|
55a911120c | ||
|
80abf90c87 | ||
|
8539591307 | ||
|
6234deeee1 | ||
|
81fabb1bfa | ||
|
8a110abc82 | ||
|
e07768412a | ||
|
ff4e5859cf | ||
|
f2e42eafc7 | ||
|
63f28ae2fe | ||
|
5b6c6141c5 | ||
|
396ef7a642 | ||
|
17f59a5665 | ||
|
10846dc97b | ||
|
17bb00727d | ||
|
bc021dbbc6 | ||
|
e3cb9c0844 | ||
|
050e2c9404 | ||
|
5ea447ba48 | ||
|
a23b063922 | ||
|
c269d57259 | ||
|
d512f327c5 | ||
|
9bf8c5a54b | ||
|
725e2f16f5 | ||
|
56b4a7f291 | ||
|
2cd4456762 | ||
|
d98d0cdad0 | ||
|
e2f4aa893f | ||
|
6b81fa89d3 | ||
|
c886587915 | ||
|
059d3eed98 | ||
|
f9ae2b4453 | ||
|
742c7ba23f | ||
|
e7ae5c5c24 | ||
|
115c5d1704 | ||
|
06209dd94c | ||
|
c8b0c939e4 | ||
|
e8d57bf636 | ||
|
0cb0af496e | ||
|
ea4443f79e | ||
|
cb8a6af12d | ||
|
14a3217d7e | ||
|
c717e7a6f6 | ||
|
f1b7847d1c | ||
|
69943af68a | ||
|
738cc5095d | ||
|
4cc4ec44b0 | ||
|
0a846cfca8 | ||
|
ea52acd7bd | ||
|
799e95c1bd | ||
|
183c191d63 | ||
|
f3e2d06922 | ||
|
99ab2566c2 | ||
|
0093276e93 | ||
|
461ef33553 | ||
|
723ea6173e | ||
|
1f214bec93 | ||
|
4b62dcfd19 | ||
|
66a8733333 | ||
|
f9ade788eb | ||
|
6d9764185b | ||
|
a944541c58 | ||
|
2f8766a9ec | ||
|
37328c78c1 | ||
|
142469be95 | ||
|
7d552b64f7 | ||
|
65fa4a34ed | ||
|
f581066747 | ||
|
29c0a7f324 | ||
|
bf9d621939 | ||
|
64a68b17f4 | ||
|
46357519e0 | ||
|
24a20c75eb | ||
|
e39bfeac08 | ||
|
874ae15d6a | ||
|
a50aeb0a66 | ||
|
983806817b | ||
|
21c9cd1caa | ||
|
c674a25eba | ||
|
f72d9a2c02 | ||
|
ab163c356f | ||
|
b3399082a8 | ||
|
26e80cec3d | ||
|
f2d39feec0 | ||
|
9b78ae5908 | ||
|
72e235ad9f | ||
|
629b919707 | ||
|
d6d016e029 | ||
|
81c4bb5f72 | ||
|
5836f8edb5 | ||
|
2c3d97d373 | ||
|
dde1ecbf5b | ||
|
ac30efb5ac | ||
|
1f684330e0 | ||
|
b042ebe4ff | ||
|
9911aa4ede | ||
|
667414a457 | ||
|
e6b3d35cdf | ||
|
e6ed3c8c5c | ||
|
392f64d33e | ||
|
aee1be1e64 | ||
|
58851f0048 | ||
|
9c4677a3c6 | ||
|
0790611b93 | ||
|
9b33d2f17e | ||
|
3e967700fd | ||
|
3322fa0294 | ||
|
178482068d | ||
|
5e6f8373e1 | ||
|
5958ef363f | ||
|
5608301178 | ||
|
faacfe3f90 | ||
|
bb88961968 | ||
|
bba298a44d | ||
|
ae6ac31d02 | ||
|
c761d75550 | ||
|
e33a7ecefa | ||
|
04598c6fb1 | ||
|
ff4dac8f3a | ||
|
1227cd8693 | ||
|
c65f845329 | ||
|
e6fc34325d | ||
|
17f0d9ce45 | ||
|
f7e017aa73 | ||
|
3e5d0eb632 | ||
|
fa8f86b672 | ||
|
2c99bd178c | ||
|
99b1fc75d3 | ||
|
78c868c075 | ||
|
1e5762fbf7 | ||
|
7f6bf95aa6 | ||
|
67f761c0e9 | ||
|
324b6529e8 | ||
|
ccde51da85 | ||
|
f6cb28eb5b | ||
|
e050d187c4 | ||
|
ea7e88d000 | ||
|
80f5683cd6 | ||
|
b698dd8f32 | ||
|
3b1b600606 | ||
|
dc2886d9b1 | ||
|
1ddc723274 | ||
|
d4082aee5a | ||
|
903342b394 | ||
|
5f1d7e5566 | ||
|
1af6528f4f | ||
|
f414f5d77a | ||
|
8117532cc7 | ||
|
ac223e64f9 | ||
|
d50bac3b3e | ||
|
6626c63bb5 | ||
|
7fe2f175aa | ||
|
13b071fd72 | ||
|
7ff368fe0d | ||
|
f8879a51fe | ||
|
57902fed22 | ||
|
24a8060f43 | ||
|
165ec62405 | ||
|
a712eca70a | ||
|
36f9b69923 | ||
|
cd382bcdda | ||
|
bd509469ab | ||
|
82c705e188 | ||
|
e1a0a855d5 | ||
|
7063541733 | ||
|
5f967fdee2 | ||
|
b7bbc938d3 | ||
|
29887c2a17 | ||
|
2b6949f3c7 | ||
|
4a6e812963 | ||
|
f8bc662620 | ||
|
f14d5ba5f2 | ||
|
493859e589 | ||
|
ba54a19d4b | ||
|
995ed77849 | ||
|
679baddd3d | ||
|
e8157ed9a2 | ||
|
4cc3f7211b | ||
|
135f15fdc3 | ||
|
04b1d2414d | ||
|
ae74fdf252 | ||
|
f0247e942e | ||
|
2859dde697 | ||
|
2c4b7c2577 | ||
|
b3d1d79a49 | ||
|
71e23e7849 | ||
|
8e0dfbcd13 | ||
|
30994710e6 | ||
|
193a7b7360 | ||
|
e15ac2fbe0 | ||
|
78f7b3340d | ||
|
4ceb9b9dbf | ||
|
3660c2dbb4 | ||
|
2b968dfd9a | ||
|
5f694d9a84 | ||
|
992de497f2 | ||
|
e9682fe003 | ||
|
dc462aa529 | ||
|
5837450a05 | ||
|
f97fc8a907 | ||
|
314ee9c74c | ||
|
a6f3e587bc | ||
|
6317053cc6 | ||
|
04570edb3f | ||
|
86322973d0 | ||
|
6406065e1f | ||
|
a988cd050b | ||
|
dee06d5777 | ||
|
7eccb38851 | ||
|
e06e9bb39c | ||
|
831c28e890 | ||
|
732b4b95db | ||
|
52f52394d5 | ||
|
416d2fb82a | ||
|
b0d1d7bdb2 | ||
|
31dcc6f685 | ||
|
c49a31e0de | ||
|
c5e8710889 | ||
|
6caec89793 | ||
|
5e75c5faff | ||
|
6bde80ad65 | ||
|
bf55cc605a | ||
|
9d67956fc8 | ||
|
b62f216c53 | ||
|
3c864322f7 | ||
|
7cf5d12ec0 | ||
|
b09c6654ec | ||
|
178cb0659a | ||
|
d1dff95ac8 | ||
|
f46fe7eeb2 | ||
|
d8b13c8c02 | ||
|
05c4b1a6a9 | ||
|
ff0a44cc12 | ||
|
a4f0234841 | ||
|
21987a67e7 | ||
|
74a09073c2 | ||
|
138d229fef | ||
|
93eb74d970 | ||
|
b7a0bf152b | ||
|
5fb6c65d23 | ||
|
200f04bf21 | ||
|
26a69458b0 | ||
|
5cb9901134 | ||
|
342ba1b599 | ||
|
7985974a58 | ||
|
2d41723cfe | ||
|
c47fdf7074 | ||
|
4dadf0ea1b | ||
|
81788790df | ||
|
268044cd01 | ||
|
b04e3dc6fd | ||
|
ecd061d46f | ||
|
1c9a1c71d3 | ||
|
efa3f228a5 | ||
|
533e383d5d | ||
|
4639e7d5c7 | ||
|
78b6cdb201 | ||
|
11fd1086af | ||
|
5b5b9ac4ef | ||
|
b20623447e | ||
|
f6e82ae0ba | ||
|
82bedb1ab5 | ||
|
33a22ae208 | ||
|
77e9acd864 | ||
|
b9010e96a0 | ||
|
27d76f5953 | ||
|
64ceb11f8c | ||
|
32d2218ff0 | ||
|
ecc308c326 | ||
|
840d9a0923 | ||
|
81faf1b582 | ||
|
ecf22e4c4f | ||
|
e8d7eb05ae | ||
|
8c5748dcc1 | ||
|
0803ac9b0b | ||
|
8cfac68317 | ||
|
e64ca7c274 | ||
|
0bb8c4832d | ||
|
b15ea58851 | ||
|
86df43879c | ||
|
4527de18d5 | ||
|
bbefe47aeb | ||
|
b19758ff71 | ||
|
401e36b885 | ||
|
6343a086e4 | ||
|
5b6bfa9ac8 | ||
|
e1336a1975 | ||
|
ca34bac479 | ||
|
4a099ab942 | ||
|
4daefe0b6e | ||
|
a040f1a9d1 | ||
|
766733b3b2 | ||
|
b392d61391 | ||
|
be3e720c57 | ||
|
e93d0dfdfc | ||
|
9be8616cc0 | ||
|
7aed35b3f0 | ||
|
f69507527b | ||
|
ae4fc9504a | ||
|
f53da62026 | ||
|
2ef337ec2e | ||
|
723b7bd532 | ||
|
4fdb11b0d8 | ||
|
fe2e6c37f4 | ||
|
4a75c55a8f | ||
|
dfb59469cf | ||
|
bdb2e1e2e9 | ||
|
c4f6f1e3d8 | ||
|
fb3eae54ea | ||
|
d3f8fce788 | ||
|
44e58a8c87 | ||
|
3d3879b0db | ||
|
a8b1eb34f3 | ||
|
fd77058def | ||
|
b147ca6c5b | ||
|
670c4cacfa | ||
|
1ed0a89303 | ||
|
ab0597da7b | ||
|
a3db6bc8fa | ||
|
9bfc8f6e27 | ||
|
6fddef2dc5 | ||
|
ec08a85aa0 | ||
|
de7af575c5 | ||
|
d3831bae4e | ||
|
0558c85b5d | ||
|
ef2ddbf86d | ||
|
778194f7a0 | ||
|
13b12a7657 | ||
|
257742de46 | ||
|
ace6385f5e | ||
|
4f8a6979d9 | ||
|
f02fceed5b | ||
|
cfd2ca3abb | ||
|
9b678e474b | ||
|
5f73c73a88 | ||
|
5f03589d3e | ||
|
089d855c47 | ||
|
750bce2b86 | ||
|
94af95c95b | ||
|
ec9944b92a | ||
|
2b95a642fc | ||
|
eb1c2f5d9f | ||
|
ac28d34ad5 | ||
|
65f33f58e9 | ||
|
86c4ded4cd | ||
|
57da71c537 | ||
|
8e34a0d3c7 | ||
|
1ad1a2d51e | ||
|
acda7bc5c4 | ||
|
618efdb326 | ||
|
b445517244 | ||
|
6e1978971a | ||
|
572293fb8b | ||
|
85cbc2437c | ||
|
228db1c063 | ||
|
97410474f5 | ||
|
e6e985af24 | ||
|
aee5d5126f | ||
|
55eb11055c | ||
|
84d6f5ed07 | ||
|
f8e1c2cfd4 | ||
|
00c1a3fd4e | ||
|
03ba8f6173 | ||
|
69740e865c | ||
|
2343f5e40f | ||
|
634a2b22dc | ||
|
b498c89860 | ||
|
ddc94030a6 | ||
|
c2f2a868c4 | ||
|
60117ae150 | ||
|
a406068f13 | ||
|
baceb2a92a | ||
|
d08f4fbace | ||
|
02a404081a | ||
|
8a8fac46e0 | ||
|
984bbf60ef | ||
|
b7f5236a0a | ||
|
6a89080ce7 | ||
|
7dea5d2fe6 | ||
|
135c80186f | ||
|
2144a9a7b2 | ||
|
86722ba05e | ||
|
be4810731a | ||
|
ac6abb363c | ||
|
5367886732 | ||
|
7a51d4ff62 | ||
|
ef564c537d | ||
|
f8fa6e4309 | ||
|
f1029596d2 | ||
|
4cd3fce555 | ||
|
082290b092 | ||
|
4a212791a2 | ||
|
6bb55ce79e | ||
|
9717a867a7 | ||
|
764166342e | ||
|
45ce0fed0a | ||
|
782ff12e6e | ||
|
af6f78a784 | ||
|
db32460f3b | ||
|
270990fe39 | ||
|
799888df2f | ||
|
933fba84a9 | ||
|
cba6273ac6 | ||
|
a10fed9d72 | ||
|
cc5699bf08 | ||
|
ad674a1c2b | ||
|
b0269faae4 | ||
|
1143efedc5 | ||
|
9e75b63925 | ||
|
940327dccf | ||
|
0270026f7c | ||
|
bf28419851 | ||
|
27b9965b10 | ||
|
be7f3ca439 | ||
|
185b6e5908 | ||
|
7ec0b8b331 | ||
|
95f92ababf | ||
|
89337091b2 | ||
|
78154f5daf | ||
|
f4db9e09c8 | ||
|
b636096ac3 | ||
|
a243ed5b23 | ||
|
3cf3780587 | ||
|
3d0a0cf376 | ||
|
7aae9d9ad3 | ||
|
870bb7efd4 | ||
|
35a6679ae9 | ||
|
a09d0117b1 | ||
|
abaac519c9 | ||
|
f9f3c7fb51 | ||
|
2000db57c8 | ||
|
9414e6d472 | ||
|
4627a565d3 | ||
|
c612cf95a8 | ||
|
1eaaa00687 | ||
|
fe4e6f24f5 | ||
|
f94bf51bb5 | ||
|
260642345d | ||
|
7cb94e6392 | ||
|
e9fe98f7f9 | ||
|
5b2e188b52 | ||
|
c1953e938d | ||
|
9d2c2d90c8 | ||
|
d24a87145d | ||
|
77bcbbcf53 | ||
|
97587fae08 | ||
|
01b54fe1a9 | ||
|
f796950493 | ||
|
495fd946bc | ||
|
6af1e25d7e | ||
|
6d47a4d7e4 | ||
|
fd5533d719 | ||
|
bc380859e8 | ||
|
1fc6ce3acd | ||
|
78d1cd79af | ||
|
a2dd017229 | ||
|
86d8c3b31a | ||
|
bc02925630 | ||
|
b9251e94a9 | ||
|
0d4ca35784 | ||
|
164cfa85da | ||
|
21da79a249 | ||
|
1b73b2a12a | ||
|
54f8f24c2c | ||
|
d530137bec | ||
|
4f722e864c | ||
|
62d38e786d | ||
|
859874487e | ||
|
b16bf29819 | ||
|
6b10dbb38c | ||
|
ea20c4b375 | ||
|
0427aeccb0 | ||
|
4898ba932d | ||
|
5142cb5e98 | ||
|
bb1efe56b6 | ||
|
9c2ba9b157 | ||
|
f51cc8fe12 | ||
|
537d7728a7 | ||
|
844ccf461f | ||
|
94542d42fa | ||
|
b223931ac0 | ||
|
42ab8d0445 | ||
|
ef237a8431 | ||
|
96364f0452 | ||
|
b73ca874bb | ||
|
a6dfa6d4e0 | ||
|
f2d99cb059 | ||
|
35a3d2306c | ||
|
cdb378066c | ||
|
85700fd80f | ||
|
73a2ad7304 | ||
|
f6c4b6b045 | ||
|
0b4d921762 | ||
|
c8a0e5228d | ||
|
832bac8c63 | ||
|
eccce7017f | ||
|
fdb1baadbe | ||
|
7623ee49e4 | ||
|
fa241dcd04 | ||
|
bee77041e8 | ||
|
50b7eb44d1 | ||
|
7b1bf82e3c | ||
|
5b7fd29797 | ||
|
ab811f70b1 | ||
|
67e3139dcf | ||
|
3257bdeed2 | ||
|
1163cc7cab | ||
|
e9e357b12e | ||
|
d246d02ab8 | ||
|
a7fbac5185 | ||
|
b45fe0ec73 | ||
|
d7e3df1974 | ||
|
31fd4efa36 | ||
|
7308912b39 | ||
|
4d103c1fc2 | ||
|
4fd92c17f0 | ||
|
6b7307df81 | ||
|
b09dd95dbd | ||
|
3353c3c205 | ||
|
ccd157dc26 | ||
|
a9d8e47979 | ||
|
30f4d1b958 | ||
|
e682d8c6e2 | ||
|
70704f67d3 | ||
|
232f78e7b6 | ||
|
b6de2cd741 | ||
|
02f81ec481 | ||
|
b7d56ad38a | ||
|
eb5ee1ffd1 | ||
|
cdec43ec06 | ||
|
0fe23c82a4 | ||
|
61cbb77042 | ||
|
bb31fc1ec7 | ||
|
6684f61a54 | ||
|
aa6f0cd55a | ||
|
f6ad018f8f | ||
|
8687c32c15 | ||
|
34b561b211 | ||
|
e32a48ac55 | ||
|
fe82e7f24d | ||
|
433c1a57e7 | ||
|
b36059fc64 | ||
|
13c9d69440 | ||
|
9c7134a865 | ||
|
d7cc2a7e9a | ||
|
f9276e28b0 | ||
|
15ad6db1a7 | ||
|
c1043ada22 | ||
|
d141122008 | ||
|
abeba39842 | ||
|
bb597a908d | ||
|
dcae2f35ce | ||
|
b06a5af069 | ||
|
a624ada8d6 | ||
|
d87366b1e7 | ||
|
5ce8a2d974 | ||
|
a42615add0 | ||
|
ecbff61332 | ||
|
e9bfe82582 | ||
|
55abe68a5f | ||
|
acf523b5fb | ||
|
0216455137 | ||
|
cb37ae6608 | ||
|
3b462906d9 | ||
|
dfb4e9c159 | ||
|
6a6814af61 | ||
|
1a7085b068 | ||
|
804d7aa4c0 | ||
|
1b1d86409c | ||
|
2520fcd284 | ||
|
b0ece4bbaa | ||
|
a18166e3f8 | ||
|
b89a859f14 | ||
|
a4aefe43dc | ||
|
115303faf5 | ||
|
1eadb00fce | ||
|
b609f8e962 | ||
|
e734971d33 | ||
|
b6c9fe86e1 | ||
|
db238a75e3 | ||
|
fb76e70c3f | ||
|
a40dce449f | ||
|
d2dd5ba0e6 | ||
|
3de8828358 | ||
|
b610b29d28 | ||
|
42234e6a09 | ||
|
4a06e20318 | ||
|
ad26db7dc8 | ||
|
5446dd92a9 | ||
|
7670ad0a72 | ||
|
b2d5f9c742 | ||
|
adf8515698 | ||
|
449afe9e6f | ||
|
0058d42ca2 | ||
|
4da385898b | ||
|
8ec8aef02e | ||
|
ed6d6575d7 | ||
|
262d778a38 | ||
|
80aa2c269b | ||
|
a3b5dcc21b | ||
|
fef9c92eb7 | ||
|
4f3d624353 | ||
|
f5e88b8293 | ||
|
faedba0407 | ||
|
adf20b60dc | ||
|
ab522dab71 | ||
|
c2a23bce50 | ||
|
bc91bd3293 | ||
|
6bf59a8dfc | ||
|
cd80cd5caa | ||
|
25d4dd82a0 | ||
|
d16a2fac80 | ||
|
2fd3c42e63 | ||
|
55e5428443 | ||
|
8375b58eac | ||
|
352f0953f3 | ||
|
bdd6f57975 | ||
|
18afe07c16 | ||
|
6baee603a5 | ||
|
5fefa606b6 | ||
|
7bc2381a45 | ||
|
2910369647 | ||
|
17f34b452e | ||
|
220f686078 | ||
|
d878d744e7 | ||
|
b31263b747 | ||
|
4a4209647e | ||
|
9860109db9 | ||
|
b8ac86939b | ||
|
9023d80d1b | ||
|
c702ffa7dd | ||
|
be8186126e | ||
|
4fda025106 | ||
|
c7f863a141 | ||
|
4aacec2de7 | ||
|
a6aae4e857 | ||
|
dde97a02f0 | ||
|
d393317eb2 | ||
|
2f3f124aa1 | ||
|
79a741486c | ||
|
c0fe65fa60 | ||
|
8de0e4ca7c | ||
|
7c179c33b5 | ||
|
177690bcb3 | ||
|
a23b3f84f0 | ||
|
d5388452d4 | ||
|
8a4206da99 | ||
|
f1084a57df | ||
|
0189a05297 | ||
|
7276b4b3ad | ||
|
93bcd413a7 | ||
|
bc25657f0a | ||
|
9db42beade | ||
|
cc1a6d60c0 | ||
|
a913587eb6 | ||
|
ae9e8ca419 | ||
|
69a8c5dc9f | ||
|
3f091470fd | ||
|
c888908cc8 | ||
|
172e2125f6 | ||
|
69f54656c4 | ||
|
c359d4a419 | ||
|
a1b8545568 | ||
|
8c0d9a1320 | ||
|
f764705629 | ||
|
3df78043c0 | ||
|
97de1c2b66 | ||
|
f7f0f49015 | ||
|
a35fa0e95a | ||
|
cddb3bb668 | ||
|
e64e3c2778 | ||
|
5e1cca1c58 | ||
|
2f181cbe41 | ||
|
e706ff0564 | ||
|
8d0e998e54 | ||
|
4f5eab4646 | ||
|
8b96c7873f | ||
|
f14471112d | ||
|
7c7b408df1 | ||
|
3bf00822b0 | ||
|
bf3a2cf393 | ||
|
c8dccec956 | ||
|
ed9c4e0c0d | ||
|
cd552ceb2b | ||
|
c4398efbbb | ||
|
8b1a527602 | ||
|
01f41a597e | ||
|
c32f1efad0 | ||
|
47c96c52b1 | ||
|
dbdb148e12 | ||
|
6a45124878 | ||
|
02d4d1a75b | ||
|
233c04a469 | ||
|
8b4f607806 | ||
|
68f06e63e2 | ||
|
67ed8b207a | ||
|
222011fc5c | ||
|
f6f7459c36 | ||
|
718bc61c88 | ||
|
015a1a6ebc | ||
|
e0a1aaa1b9 | ||
|
7f4dabf546 | ||
|
beb2ef121e | ||
|
5a04d982d9 | ||
|
35bfd0b88f | ||
|
9351f300b0 | ||
|
0d678120e4 | ||
|
5766ea9541 | ||
|
6d8bc84db3 | ||
|
823910b69e | ||
|
aa801d9cc6 | ||
|
067acce4de | ||
|
6999c6b0cf | ||
|
da18aae2d8 | ||
|
6362ca1052 | ||
|
022e1b0c02 | ||
|
94c0b9fc06 | ||
|
5eff4f9816 | ||
|
fb229fcae8 | ||
|
50b35ac4bc | ||
|
ea727546d6 | ||
|
18a7d15d14 | ||
|
be24475cee | ||
|
8066c7dec6 | ||
|
896cd27bea | ||
|
1ffde403f0 | ||
|
b69b927795 | ||
|
6840f27bc6 | ||
|
4a34855a92 | ||
|
b3f7f379df | ||
|
4994e46ad0 | ||
|
1382f7a3dc | ||
|
b973455037 | ||
|
a5136a1021 | ||
|
d9e996def5 | ||
|
224228e448 | ||
|
c8372a3aa5 | ||
|
2135691b90 | ||
|
ea508b2629 | ||
|
09cd79772f | ||
|
7b5db6521c | ||
|
27eba3cd46 | ||
|
41c7414d97 | ||
|
fd7c92879c | ||
|
e7971f5a67 | ||
|
72f9d85bbe | ||
|
956cc6a85c | ||
|
015c50bbdb | ||
|
b6f0893c33 | ||
|
7c92287f97 | ||
|
53a59412bb | ||
|
d78acd480a | ||
|
17930a6d66 | ||
|
d825ac346e | ||
|
fa53055485 | ||
|
b4cba01870 | ||
|
70e368a57e | ||
|
004eccec89 | ||
|
36c01042c1 | ||
|
bd3f0da385 | ||
|
9450744b3b | ||
|
1c03c83c0a | ||
|
fdab23c3f9 | ||
|
7b08e625b4 | ||
|
2102a104d2 | ||
|
3e1aee4cbc | ||
|
b5b01d97f1 | ||
|
02581bbf02 | ||
|
4ac85829c8 | ||
|
ad50136dbd | ||
|
20c4f84a4e | ||
|
bf38db0035 | ||
|
b8c363a82c | ||
|
9393dcddb7 | ||
|
5b434ee336 | ||
|
6ba6334512 | ||
|
8de7a2e3c7 | ||
|
197ac8b950 | ||
|
1958a149c3 | ||
|
7bbbda8d2b | ||
|
5d87a74c3c | ||
|
1f488b00f8 | ||
|
570725293c | ||
|
732b9e47c8 | ||
|
ea75c8864f | ||
|
9514a38320 | ||
|
d94e79d57a | ||
|
02c592d6af | ||
|
d51d584aed | ||
|
e5fd9819da | ||
|
00c3b0d888 | ||
|
aa44c54a19 | ||
|
9940d0281b | ||
|
586a0b12ab | ||
|
75f0384a15 | ||
|
56f51d3e35 | ||
|
7135a919e3 | ||
|
9d6bd359c4 | ||
|
f739644735 | ||
|
b63bc72450 | ||
|
683069cb98 | ||
|
cf20e67f1f | ||
|
74d10b9824 | ||
|
61d4bc1430 | ||
|
07c7bb8b2a | ||
|
9ce7779bde | ||
|
9e10126505 | ||
|
cfef72ae57 | ||
|
86bfc7ada8 | ||
|
0de75aeee1 | ||
|
075550b7ba | ||
|
e5bb1b2cc6 | ||
|
85aca4f095 | ||
|
745eea9a29 | ||
|
d586e7df33 | ||
|
6d4711ce43 | ||
|
8a84addc54 | ||
|
1879db9f8f | ||
|
869ec3f670 | ||
|
70df4ca461 | ||
|
06ee8fdd47 | ||
|
5467685bd8 | ||
|
efaf75f2e6 | ||
|
ca430f0e7b | ||
|
fa61ad072d | ||
|
686598b6b3 | ||
|
5f5dcec0b9 | ||
|
2a5cb8da32 | ||
|
9b497aebb4 | ||
|
5f08883227 | ||
|
4b2073ca59 | ||
|
f98487ef18 | ||
|
dff964582b | ||
|
e5c36c8d56 | ||
|
d765b92cca | ||
|
ba266ab13c | ||
|
d4aa981fd7 | ||
|
ac0d0b21e2 | ||
|
092ab823d1 | ||
|
3ad2456dd9 | ||
|
146ec4e760 | ||
|
f563817b98 | ||
|
ec15a66a68 | ||
|
e708e30c33 | ||
|
383dd80919 | ||
|
6752bd450b | ||
|
b0780e1db5 | ||
|
02a5df0aee | ||
|
cb4a48ca02 | ||
|
64f997718a | ||
|
482cf261c0 | ||
|
1a5706a693 | ||
|
13c320902e | ||
|
bfbd01a4e5 | ||
|
09622e180e | ||
|
84486bad78 | ||
|
c486baccaa | ||
|
57554aba57 | ||
|
c9eb1a2e9c | ||
|
1a64489121 | ||
|
888ffc002f | ||
|
58419f14e8 | ||
|
57a5c7c8b6 | ||
|
b2b40d9ed6 | ||
|
8e578227c3 | ||
|
267dfac737 | ||
|
a08ffdc8d3 | ||
|
1ef4332af6 | ||
|
d0d2fd7918 | ||
|
c518c4756b | ||
|
a3a99cc631 | ||
|
977a55e3b8 | ||
|
002db3c3e9 | ||
|
d9e44bab69 | ||
|
4b93fc61b5 | ||
|
214b5efd72 | ||
|
9bd822d693 | ||
|
bf89eaae25 | ||
|
f9b359ae30 | ||
|
24ed003471 | ||
|
a835750252 | ||
|
ad07bdb62b | ||
|
41104324ec | ||
|
e9344ae101 | ||
|
56a9167ed2 | ||
|
e0b90c4b36 | ||
|
976902f22c | ||
|
0f69c58ba9 | ||
|
1e6c96c6eb | ||
|
63b14d14c1 | ||
|
6aaaba6419 | ||
|
3b8e736fe3 | ||
|
68841b3d8a | ||
|
3d8afe7cb8 | ||
|
8595242142 | ||
|
ebe7bc0686 | ||
|
4ab180f016 | ||
|
372649069e | ||
|
98df46f3ea | ||
|
269fb23527 | ||
|
ad5cbf0da6 | ||
|
10cdf64f90 | ||
|
ec8e639804 | ||
|
37f37f7287 | ||
|
ef7d68bfd6 | ||
|
058b012e6c | ||
|
71370758a8 | ||
|
38a44676eb | ||
|
05ce3d35b3 | ||
|
2151086b0a | ||
|
9c83af3789 | ||
|
ac3eecc879 | ||
|
ec0910e3da | ||
|
fd0c26cd56 | ||
|
a4c5dee082 | ||
|
37c09dbdb6 | ||
|
73d1973625 | ||
|
5a04a886cf | ||
|
50802f84f0 | ||
|
138b68ecc0 | ||
|
e0b01ee94e | ||
|
4f2c3df518 | ||
|
51a6bb1c22 | ||
|
6bf9ec69f3 | ||
|
21309eeb5d | ||
|
0a1b46c52f | ||
|
9512f9eec3 | ||
|
ab94422c18 | ||
|
ec105e5265 | ||
|
cadd8521ae | ||
|
8825c50671 | ||
|
a72cc3c248 | ||
|
780f7254c1 | ||
|
37621e77ae | ||
|
8017386c73 | ||
|
a5f4c25a2c | ||
|
1d7bddf449 | ||
|
711bdaf373 | ||
|
803d9c5a8e | ||
|
1133c41fa8 | ||
|
a06af7ee93 | ||
|
c54717707e | ||
|
440d83d754 | ||
|
1cf62916a7 | ||
|
e3958d4adb | ||
|
dfccd4abf9 | ||
|
994d6f552c | ||
|
b015611a2a | ||
|
f4e362c5d0 | ||
|
a542236614 | ||
|
651439ea06 | ||
|
eda450838e | ||
|
b906daa493 | ||
|
ac668dce7d | ||
|
1bb4d62a3e | ||
|
0b970f9a85 | ||
|
d2b695e7b5 | ||
|
b2f23c1a5e | ||
|
f403afb012 | ||
|
ee276aff44 | ||
|
0acd1dc5d1 | ||
|
21815e1621 | ||
|
15933bb16f | ||
|
930cd0dc50 | ||
|
fc4af48179 | ||
|
ba1cf84ea5 | ||
|
59cf01e252 | ||
|
46e681f4fc |
7462 changed files with 356786 additions and 124324 deletions
|
@ -14,6 +14,7 @@ core: &core
|
||||||
base_platforms: &base_platforms
|
base_platforms: &base_platforms
|
||||||
- homeassistant/components/air_quality/**
|
- homeassistant/components/air_quality/**
|
||||||
- homeassistant/components/alarm_control_panel/**
|
- homeassistant/components/alarm_control_panel/**
|
||||||
|
- homeassistant/components/assist_satellite/**
|
||||||
- homeassistant/components/binary_sensor/**
|
- homeassistant/components/binary_sensor/**
|
||||||
- homeassistant/components/button/**
|
- homeassistant/components/button/**
|
||||||
- homeassistant/components/calendar/**
|
- homeassistant/components/calendar/**
|
||||||
|
@ -61,6 +62,7 @@ components: &components
|
||||||
- homeassistant/components/auth/**
|
- homeassistant/components/auth/**
|
||||||
- homeassistant/components/automation/**
|
- homeassistant/components/automation/**
|
||||||
- homeassistant/components/backup/**
|
- homeassistant/components/backup/**
|
||||||
|
- homeassistant/components/blueprint/**
|
||||||
- homeassistant/components/bluetooth/**
|
- homeassistant/components/bluetooth/**
|
||||||
- homeassistant/components/cloud/**
|
- homeassistant/components/cloud/**
|
||||||
- homeassistant/components/config/**
|
- homeassistant/components/config/**
|
||||||
|
@ -77,6 +79,7 @@ components: &components
|
||||||
- homeassistant/components/group/**
|
- homeassistant/components/group/**
|
||||||
- homeassistant/components/hassio/**
|
- homeassistant/components/hassio/**
|
||||||
- homeassistant/components/homeassistant/**
|
- homeassistant/components/homeassistant/**
|
||||||
|
- homeassistant/components/homeassistant_hardware/**
|
||||||
- homeassistant/components/http/**
|
- homeassistant/components/http/**
|
||||||
- homeassistant/components/image/**
|
- homeassistant/components/image/**
|
||||||
- homeassistant/components/input_boolean/**
|
- homeassistant/components/input_boolean/**
|
||||||
|
@ -109,6 +112,7 @@ components: &components
|
||||||
- homeassistant/components/tag/**
|
- homeassistant/components/tag/**
|
||||||
- homeassistant/components/template/**
|
- homeassistant/components/template/**
|
||||||
- homeassistant/components/timer/**
|
- homeassistant/components/timer/**
|
||||||
|
- homeassistant/components/trace/**
|
||||||
- homeassistant/components/usb/**
|
- homeassistant/components/usb/**
|
||||||
- homeassistant/components/webhook/**
|
- homeassistant/components/webhook/**
|
||||||
- homeassistant/components/websocket_api/**
|
- homeassistant/components/websocket_api/**
|
||||||
|
@ -124,9 +128,12 @@ tests: &tests
|
||||||
- tests/*.py
|
- tests/*.py
|
||||||
- tests/auth/**
|
- tests/auth/**
|
||||||
- tests/backports/**
|
- tests/backports/**
|
||||||
|
- tests/components/conftest.py
|
||||||
|
- tests/components/diagnostics/**
|
||||||
- tests/components/history/**
|
- tests/components/history/**
|
||||||
- tests/components/logbook/**
|
- tests/components/logbook/**
|
||||||
- tests/components/recorder/**
|
- tests/components/recorder/**
|
||||||
|
- tests/components/repairs/**
|
||||||
- tests/components/sensor/**
|
- tests/components/sensor/**
|
||||||
- tests/hassfest/**
|
- tests/hassfest/**
|
||||||
- tests/helpers/**
|
- tests/helpers/**
|
||||||
|
@ -146,6 +153,7 @@ requirements: &requirements
|
||||||
- homeassistant/package_constraints.txt
|
- homeassistant/package_constraints.txt
|
||||||
- requirements*.txt
|
- requirements*.txt
|
||||||
- pyproject.toml
|
- pyproject.toml
|
||||||
|
- script/licenses.py
|
||||||
|
|
||||||
any:
|
any:
|
||||||
- *base_platforms
|
- *base_platforms
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Home Assistant Dev",
|
"name": "Home Assistant Dev",
|
||||||
"context": "..",
|
"context": "..",
|
||||||
"dockerFile": "../Dockerfile.dev",
|
"dockerFile": "../Dockerfile.dev",
|
||||||
"postCreateCommand": "script/setup",
|
"postCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && script/setup",
|
||||||
"postStartCommand": "script/bootstrap",
|
"postStartCommand": "script/bootstrap",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"PYTHONASYNCIODEBUG": "1"
|
"PYTHONASYNCIODEBUG": "1"
|
||||||
|
@ -12,7 +12,12 @@
|
||||||
},
|
},
|
||||||
// Port 5683 udp is used by Shelly integration
|
// Port 5683 udp is used by Shelly integration
|
||||||
"appPort": ["8123:8123", "5683:5683/udp"],
|
"appPort": ["8123:8123", "5683:5683/udp"],
|
||||||
"runArgs": ["-e", "GIT_EDITOR=code --wait"],
|
"runArgs": [
|
||||||
|
"-e",
|
||||||
|
"GIT_EDITOR=code --wait",
|
||||||
|
"--security-opt",
|
||||||
|
"label=disable"
|
||||||
|
],
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
|
@ -53,7 +58,13 @@
|
||||||
],
|
],
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||||
}
|
},
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["homeassistant/components/*/manifest.json"],
|
||||||
|
"url": "./script/json_schemas/manifest_schema.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ docs
|
||||||
# Development
|
# Development
|
||||||
.devcontainer
|
.devcontainer
|
||||||
.vscode
|
.vscode
|
||||||
|
.tool-versions
|
||||||
|
|
||||||
# Test related files
|
# Test related files
|
||||||
tests
|
tests
|
||||||
|
|
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
@ -1,2 +1 @@
|
||||||
custom: https://www.nabucasa.com
|
custom: https://www.openhomefoundation.org
|
||||||
github: balloob
|
|
||||||
|
|
84
.github/workflows/builder.yml
vendored
84
.github/workflows/builder.yml
vendored
|
@ -10,7 +10,7 @@ on:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: core
|
BUILD_TYPE: core
|
||||||
DEFAULT_PYTHON: "3.12"
|
DEFAULT_PYTHON: "3.13"
|
||||||
PIP_TIMEOUT: 60
|
PIP_TIMEOUT: 60
|
||||||
UV_HTTP_TIMEOUT: 60
|
UV_HTTP_TIMEOUT: 60
|
||||||
UV_SYSTEM_PYTHON: "true"
|
UV_SYSTEM_PYTHON: "true"
|
||||||
|
@ -27,12 +27,12 @@ jobs:
|
||||||
publish: ${{ steps.version.outputs.publish }}
|
publish: ${{ steps.version.outputs.publish }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ jobs:
|
||||||
run: find ./homeassistant/components/*/translations -name "*.json" | tar zcvf translations.tar.gz -T -
|
run: find ./homeassistant/components/*/translations -name "*.json" | tar zcvf translations.tar.gz -T -
|
||||||
|
|
||||||
- name: Upload translations
|
- name: Upload translations
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: translations
|
name: translations
|
||||||
path: translations.tar.gz
|
path: translations.tar.gz
|
||||||
|
@ -90,7 +90,7 @@ jobs:
|
||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Download nightly wheels of frontend
|
- name: Download nightly wheels of frontend
|
||||||
if: needs.init.outputs.channel == 'dev'
|
if: needs.init.outputs.channel == 'dev'
|
||||||
|
@ -116,7 +116,7 @@ jobs:
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
if: needs.init.outputs.channel == 'dev'
|
if: needs.init.outputs.channel == 'dev'
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
UV_PRERELEASE: allow
|
UV_PRERELEASE: allow
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install "$(grep '^uv' < requirements_test.txt)"
|
python3 -m pip install "$(grep '^uv' < requirements.txt)"
|
||||||
uv pip install packaging tomli
|
uv pip install packaging tomli
|
||||||
uv pip install .
|
uv pip install .
|
||||||
python3 script/version_bump.py nightly --set-nightly-version "${{ needs.init.outputs.version }}"
|
python3 script/version_bump.py nightly --set-nightly-version "${{ needs.init.outputs.version }}"
|
||||||
|
@ -197,7 +197,7 @@ jobs:
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build base image
|
- name: Build base image
|
||||||
uses: home-assistant/builder@2024.03.5
|
uses: home-assistant/builder@2024.08.2
|
||||||
with:
|
with:
|
||||||
args: |
|
args: |
|
||||||
$BUILD_ARGS \
|
$BUILD_ARGS \
|
||||||
|
@ -242,7 +242,7 @@ jobs:
|
||||||
- green
|
- green
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Set build additional args
|
- name: Set build additional args
|
||||||
run: |
|
run: |
|
||||||
|
@ -263,7 +263,7 @@ jobs:
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build base image
|
- name: Build base image
|
||||||
uses: home-assistant/builder@2024.03.5
|
uses: home-assistant/builder@2024.08.2
|
||||||
with:
|
with:
|
||||||
args: |
|
args: |
|
||||||
$BUILD_ARGS \
|
$BUILD_ARGS \
|
||||||
|
@ -279,7 +279,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Initialize git
|
- name: Initialize git
|
||||||
uses: home-assistant/actions/helpers/git-init@master
|
uses: home-assistant/actions/helpers/git-init@master
|
||||||
|
@ -316,14 +316,15 @@ jobs:
|
||||||
packages: write
|
packages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
registry: ["ghcr.io/home-assistant", "docker.io/homeassistant"]
|
registry: ["ghcr.io/home-assistant", "docker.io/homeassistant"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Install Cosign
|
- name: Install Cosign
|
||||||
uses: sigstore/cosign-installer@v3.5.0
|
uses: sigstore/cosign-installer@v3.7.0
|
||||||
with:
|
with:
|
||||||
cosign-release: "v2.2.3"
|
cosign-release: "v2.2.3"
|
||||||
|
|
||||||
|
@ -450,10 +451,10 @@ jobs:
|
||||||
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
if: github.repository_owner == 'home-assistant' && needs.init.outputs.publish == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
|
@ -482,3 +483,56 @@ jobs:
|
||||||
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
||||||
|
|
||||||
twine upload dist/* --skip-existing
|
twine upload dist/* --skip-existing
|
||||||
|
|
||||||
|
hassfest-image:
|
||||||
|
name: Build and test hassfest image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
needs: ["init"]
|
||||||
|
if: github.repository_owner == 'home-assistant'
|
||||||
|
env:
|
||||||
|
HASSFEST_IMAGE_NAME: ghcr.io/home-assistant/hassfest
|
||||||
|
HASSFEST_IMAGE_TAG: ghcr.io/home-assistant/hassfest:${{ needs.init.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
|
||||||
|
with:
|
||||||
|
context: . # So action will not pull the repository again
|
||||||
|
file: ./script/hassfest/docker/Dockerfile
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.HASSFEST_IMAGE_TAG }}
|
||||||
|
|
||||||
|
- name: Run hassfest against core
|
||||||
|
run: docker run --rm -v ${{ github.workspace }}/homeassistant:/github/workspace/homeassistant ${{ env.HASSFEST_IMAGE_TAG }} --core-integrations-path=/github/workspace/homeassistant/components
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
if: needs.init.outputs.channel != 'dev' && needs.init.outputs.publish == 'true'
|
||||||
|
id: push
|
||||||
|
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
|
||||||
|
with:
|
||||||
|
context: . # So action will not pull the repository again
|
||||||
|
file: ./script/hassfest/docker/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.HASSFEST_IMAGE_TAG }},${{ env.HASSFEST_IMAGE_NAME }}:latest
|
||||||
|
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
if: needs.init.outputs.channel != 'dev' && needs.init.outputs.publish == 'true'
|
||||||
|
uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4
|
||||||
|
with:
|
||||||
|
subject-name: ${{ env.HASSFEST_IMAGE_NAME }}
|
||||||
|
subject-digest: ${{ steps.push.outputs.digest }}
|
||||||
|
push-to-registry: true
|
||||||
|
|
253
.github/workflows/ci.yaml
vendored
253
.github/workflows/ci.yaml
vendored
|
@ -31,14 +31,18 @@ on:
|
||||||
description: "Only run mypy"
|
description: "Only run mypy"
|
||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
audit-licenses-only:
|
||||||
|
description: "Only run audit licenses"
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CACHE_VERSION: 9
|
CACHE_VERSION: 11
|
||||||
UV_CACHE_VERSION: 1
|
UV_CACHE_VERSION: 1
|
||||||
MYPY_CACHE_VERSION: 8
|
MYPY_CACHE_VERSION: 9
|
||||||
HA_SHORT_VERSION: "2024.8"
|
HA_SHORT_VERSION: "2024.12"
|
||||||
DEFAULT_PYTHON: "3.12"
|
DEFAULT_PYTHON: "3.12"
|
||||||
ALL_PYTHON_VERSIONS: "['3.12']"
|
ALL_PYTHON_VERSIONS: "['3.12', '3.13']"
|
||||||
# 10.3 is the oldest supported version
|
# 10.3 is the oldest supported version
|
||||||
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
|
# - 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 is the current long-term-support
|
||||||
|
@ -89,7 +93,7 @@ jobs:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Generate partial Python venv restore key
|
- name: Generate partial Python venv restore key
|
||||||
id: generate_python_cache_key
|
id: generate_python_cache_key
|
||||||
run: |
|
run: |
|
||||||
|
@ -222,20 +226,21 @@ jobs:
|
||||||
if: |
|
if: |
|
||||||
github.event.inputs.pylint-only != 'true'
|
github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.0.2
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
key: >-
|
key: >-
|
||||||
|
@ -247,11 +252,11 @@ jobs:
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pip install "$(grep '^uv' < requirements_test.txt)"
|
pip install "$(grep '^uv' < requirements.txt)"
|
||||||
uv pip install "$(cat requirements_test.txt | grep pre-commit)"
|
uv pip install "$(cat requirements_test.txt | grep pre-commit)"
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache@v4.0.2
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
lookup-only: true
|
lookup-only: true
|
||||||
|
@ -272,16 +277,16 @@ jobs:
|
||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -290,7 +295,7 @@ jobs:
|
||||||
needs.info.outputs.pre-commit_cache_key }}
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -312,16 +317,16 @@ jobs:
|
||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -330,7 +335,7 @@ jobs:
|
||||||
needs.info.outputs.pre-commit_cache_key }}
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -343,6 +348,7 @@ jobs:
|
||||||
pre-commit run --hook-stage manual ruff --all-files --show-diff-on-failure
|
pre-commit run --hook-stage manual ruff --all-files --show-diff-on-failure
|
||||||
env:
|
env:
|
||||||
RUFF_OUTPUT_FORMAT: github
|
RUFF_OUTPUT_FORMAT: github
|
||||||
|
|
||||||
lint-other:
|
lint-other:
|
||||||
name: Check other linters
|
name: Check other linters
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
@ -351,16 +357,16 @@ jobs:
|
||||||
- pre-commit
|
- pre-commit
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -369,7 +375,7 @@ jobs:
|
||||||
needs.info.outputs.pre-commit_cache_key }}
|
needs.info.outputs.pre-commit_cache_key }}
|
||||||
- name: Restore pre-commit environment from cache
|
- name: Restore pre-commit environment from cache
|
||||||
id: cache-precommit
|
id: cache-precommit
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PRE_COMMIT_CACHE }}
|
path: ${{ env.PRE_COMMIT_CACHE }}
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -423,17 +429,32 @@ jobs:
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pre-commit run --show-diff-on-failure --hook-stage manual codespell --all-files
|
pre-commit run --show-diff-on-failure --hook-stage manual codespell --all-files
|
||||||
|
|
||||||
|
lint-hadolint:
|
||||||
|
name: Check ${{ matrix.file }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs:
|
||||||
|
- info
|
||||||
|
if: |
|
||||||
|
github.event.inputs.pylint-only != 'true'
|
||||||
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
file:
|
||||||
|
- Dockerfile
|
||||||
|
- Dockerfile.dev
|
||||||
|
- script/hassfest/docker/Dockerfile
|
||||||
|
steps:
|
||||||
|
- name: Check out code from GitHub
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Register hadolint problem matcher
|
- name: Register hadolint problem matcher
|
||||||
run: |
|
run: |
|
||||||
echo "::add-matcher::.github/workflows/matchers/hadolint.json"
|
echo "::add-matcher::.github/workflows/matchers/hadolint.json"
|
||||||
- name: Check Dockerfile
|
- name: Check ${{ matrix.file }}
|
||||||
uses: docker://hadolint/hadolint:v1.18.2
|
uses: docker://hadolint/hadolint:v2.12.0
|
||||||
with:
|
with:
|
||||||
args: hadolint Dockerfile
|
args: hadolint ${{ matrix.file }}
|
||||||
- name: Check Dockerfile.dev
|
|
||||||
uses: docker://hadolint/hadolint:v1.18.2
|
|
||||||
with:
|
|
||||||
args: hadolint Dockerfile.dev
|
|
||||||
|
|
||||||
base:
|
base:
|
||||||
name: Prepare dependencies
|
name: Prepare dependencies
|
||||||
|
@ -445,23 +466,23 @@ jobs:
|
||||||
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
|
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Generate partial uv restore key
|
- name: Generate partial uv restore key
|
||||||
id: generate-uv-key
|
id: generate-uv-key
|
||||||
run: |
|
run: |
|
||||||
uv_version=$(cat requirements_test.txt | grep uv | cut -d '=' -f 3)
|
uv_version=$(cat requirements.txt | grep uv | cut -d '=' -f 3)
|
||||||
echo "version=${uv_version}" >> $GITHUB_OUTPUT
|
echo "version=${uv_version}" >> $GITHUB_OUTPUT
|
||||||
echo "key=uv-${{ env.UV_CACHE_VERSION }}-${uv_version}-${{
|
echo "key=uv-${{ env.UV_CACHE_VERSION }}-${uv_version}-${{
|
||||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.0.2
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
lookup-only: true
|
lookup-only: true
|
||||||
|
@ -470,7 +491,7 @@ jobs:
|
||||||
needs.info.outputs.python_cache_key }}
|
needs.info.outputs.python_cache_key }}
|
||||||
- name: Restore uv wheel cache
|
- name: Restore uv wheel cache
|
||||||
if: steps.cache-venv.outputs.cache-hit != 'true'
|
if: steps.cache-venv.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v4.0.2
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.UV_CACHE_DIR }}
|
path: ${{ env.UV_CACHE_DIR }}
|
||||||
key: >-
|
key: >-
|
||||||
|
@ -504,12 +525,11 @@ jobs:
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pip install "$(grep '^uv' < requirements_test.txt)"
|
pip install "$(grep '^uv' < requirements.txt)"
|
||||||
uv pip install -U "pip>=21.3.1" setuptools wheel
|
uv pip install -U "pip>=21.3.1" setuptools wheel
|
||||||
uv pip install -r requirements.txt
|
uv pip install -r requirements.txt
|
||||||
python -m script.gen_requirements_all ci
|
python -m script.gen_requirements_all ci
|
||||||
uv pip install -r requirements_all_pytest.txt
|
uv pip install -r requirements_all_pytest.txt -r requirements_test.txt
|
||||||
uv pip install -r requirements_test.txt
|
|
||||||
uv pip install -e . --config-settings editable_mode=compat
|
uv pip install -e . --config-settings editable_mode=compat
|
||||||
|
|
||||||
hassfest:
|
hassfest:
|
||||||
|
@ -518,6 +538,7 @@ jobs:
|
||||||
if: |
|
if: |
|
||||||
github.event.inputs.pylint-only != 'true'
|
github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
|
@ -529,16 +550,16 @@ jobs:
|
||||||
sudo apt-get -y install \
|
sudo apt-get -y install \
|
||||||
libturbojpeg
|
libturbojpeg
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -556,21 +577,22 @@ jobs:
|
||||||
if: |
|
if: |
|
||||||
github.event.inputs.pylint-only != 'true'
|
github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -589,38 +611,45 @@ jobs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
if: |
|
if: |
|
||||||
needs.info.outputs.requirements == 'true'
|
(github.event.inputs.pylint-only != 'true'
|
||||||
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
|| github.event.inputs.audit-licenses-only == 'true')
|
||||||
|
&& needs.info.outputs.requirements == 'true'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: ${{ fromJson(needs.info.outputs.python_versions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
key: >-
|
key: >-
|
||||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
needs.info.outputs.python_cache_key }}
|
needs.info.outputs.python_cache_key }}
|
||||||
- name: Run pip-licenses
|
- name: Extract license data
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pip-licenses --format=json --output-file=licenses.json
|
python -m script.licenses extract --output-file=licenses-${{ matrix.python-version }}.json
|
||||||
- name: Upload licenses
|
- name: Upload licenses
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: licenses
|
name: licenses-${{ github.run_number }}-${{ matrix.python-version }}
|
||||||
path: licenses.json
|
path: licenses-${{ matrix.python-version }}.json
|
||||||
- name: Process licenses
|
- name: Check licenses
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python -m script.licenses
|
python -m script.licenses check licenses-${{ matrix.python-version }}.json
|
||||||
|
|
||||||
pylint:
|
pylint:
|
||||||
name: Check pylint
|
name: Check pylint
|
||||||
|
@ -628,22 +657,23 @@ jobs:
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
if: |
|
if: |
|
||||||
github.event.inputs.mypy-only != 'true'
|
github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
|| github.event.inputs.pylint-only == 'true'
|
|| github.event.inputs.pylint-only == 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -672,23 +702,25 @@ jobs:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
if: |
|
if: |
|
||||||
(github.event.inputs.mypy-only != 'true' || github.event.inputs.pylint-only == 'true')
|
(github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
|
|| github.event.inputs.pylint-only == 'true')
|
||||||
&& (needs.info.outputs.tests_glob || needs.info.outputs.test_full_suite == 'true')
|
&& (needs.info.outputs.tests_glob || needs.info.outputs.test_full_suite == 'true')
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -703,30 +735,31 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pylint --ignore-missing-annotations=y tests
|
pylint tests
|
||||||
- name: Run pylint (partially)
|
- name: Run pylint (partially)
|
||||||
if: needs.info.outputs.test_full_suite == 'false'
|
if: needs.info.outputs.test_full_suite == 'false'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pylint --ignore-missing-annotations=y tests/components/${{ needs.info.outputs.tests_glob }}
|
pylint tests/components/${{ needs.info.outputs.tests_glob }}
|
||||||
|
|
||||||
mypy:
|
mypy:
|
||||||
name: Check mypy
|
name: Check mypy
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
if: |
|
if: |
|
||||||
github.event.inputs.pylint-only != 'true'
|
github.event.inputs.pylint-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
|| github.event.inputs.mypy-only == 'true'
|
|| github.event.inputs.mypy-only == 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
- base
|
- base
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -739,7 +772,7 @@ jobs:
|
||||||
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
|
||||||
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -747,7 +780,7 @@ jobs:
|
||||||
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
|
||||||
needs.info.outputs.python_cache_key }}
|
needs.info.outputs.python_cache_key }}
|
||||||
- name: Restore mypy cache
|
- name: Restore mypy cache
|
||||||
uses: actions/cache@v4.0.2
|
uses: actions/cache@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: .mypy_cache
|
path: .mypy_cache
|
||||||
key: >-
|
key: >-
|
||||||
|
@ -781,6 +814,7 @@ jobs:
|
||||||
&& github.event.inputs.lint-only != 'true'
|
&& github.event.inputs.lint-only != 'true'
|
||||||
&& github.event.inputs.pylint-only != 'true'
|
&& github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
&& needs.info.outputs.test_full_suite == 'true'
|
&& needs.info.outputs.test_full_suite == 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
|
@ -797,16 +831,16 @@ jobs:
|
||||||
libturbojpeg \
|
libturbojpeg \
|
||||||
libgammu-dev
|
libgammu-dev
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore base Python virtual environment
|
- name: Restore base Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -818,7 +852,7 @@ jobs:
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python -m script.split_tests ${{ needs.info.outputs.test_group_count }} tests
|
python -m script.split_tests ${{ needs.info.outputs.test_group_count }} tests
|
||||||
- name: Upload pytest_buckets
|
- name: Upload pytest_buckets
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: pytest_buckets
|
name: pytest_buckets
|
||||||
path: pytest_buckets.txt
|
path: pytest_buckets.txt
|
||||||
|
@ -831,6 +865,7 @@ jobs:
|
||||||
&& github.event.inputs.lint-only != 'true'
|
&& github.event.inputs.lint-only != 'true'
|
||||||
&& github.event.inputs.pylint-only != 'true'
|
&& github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
&& needs.info.outputs.test_full_suite == 'true'
|
&& needs.info.outputs.test_full_suite == 'true'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
|
@ -860,16 +895,16 @@ jobs:
|
||||||
libturbojpeg \
|
libturbojpeg \
|
||||||
libgammu-dev
|
libgammu-dev
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -904,11 +939,13 @@ jobs:
|
||||||
cov_params+=(--cov-report=xml)
|
cov_params+=(--cov-report=xml)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Test group ${{ matrix.group }}: $(sed -n "${{ matrix.group }},1p" pytest_buckets.txt)"
|
||||||
python3 -b -X dev -m pytest \
|
python3 -b -X dev -m pytest \
|
||||||
-qq \
|
-qq \
|
||||||
--timeout=9 \
|
--timeout=9 \
|
||||||
--durations=10 \
|
--durations=10 \
|
||||||
-n auto \
|
--numprocesses auto \
|
||||||
|
--snapshot-details \
|
||||||
--dist=loadfile \
|
--dist=loadfile \
|
||||||
${cov_params[@]} \
|
${cov_params[@]} \
|
||||||
-o console_output_style=count \
|
-o console_output_style=count \
|
||||||
|
@ -917,14 +954,14 @@ jobs:
|
||||||
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
||||||
- name: Upload pytest output
|
- name: Upload pytest output
|
||||||
if: success() || failure() && steps.pytest-full.conclusion == 'failure'
|
if: success() || failure() && steps.pytest-full.conclusion == 'failure'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
||||||
path: pytest-*.txt
|
path: pytest-*.txt
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
if: needs.info.outputs.skip_coverage != 'true'
|
if: needs.info.outputs.skip_coverage != 'true'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
@ -950,6 +987,7 @@ jobs:
|
||||||
&& github.event.inputs.lint-only != 'true'
|
&& github.event.inputs.lint-only != 'true'
|
||||||
&& github.event.inputs.pylint-only != 'true'
|
&& github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
&& needs.info.outputs.mariadb_groups != '[]'
|
&& needs.info.outputs.mariadb_groups != '[]'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
|
@ -978,16 +1016,16 @@ jobs:
|
||||||
libturbojpeg \
|
libturbojpeg \
|
||||||
libmariadb-dev-compat
|
libmariadb-dev-compat
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -1029,7 +1067,8 @@ jobs:
|
||||||
python3 -b -X dev -m pytest \
|
python3 -b -X dev -m pytest \
|
||||||
-qq \
|
-qq \
|
||||||
--timeout=20 \
|
--timeout=20 \
|
||||||
-n 1 \
|
--numprocesses 1 \
|
||||||
|
--snapshot-details \
|
||||||
${cov_params[@]} \
|
${cov_params[@]} \
|
||||||
-o console_output_style=count \
|
-o console_output_style=count \
|
||||||
--durations=10 \
|
--durations=10 \
|
||||||
|
@ -1042,7 +1081,7 @@ jobs:
|
||||||
2>&1 | tee pytest-${{ matrix.python-version }}-${mariadb}.txt
|
2>&1 | tee pytest-${{ matrix.python-version }}-${mariadb}.txt
|
||||||
- name: Upload pytest output
|
- name: Upload pytest output
|
||||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
||||||
steps.pytest-partial.outputs.mariadb }}
|
steps.pytest-partial.outputs.mariadb }}
|
||||||
|
@ -1050,7 +1089,7 @@ jobs:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
if: needs.info.outputs.skip_coverage != 'true'
|
if: needs.info.outputs.skip_coverage != 'true'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.python-version }}-${{
|
name: coverage-${{ matrix.python-version }}-${{
|
||||||
steps.pytest-partial.outputs.mariadb }}
|
steps.pytest-partial.outputs.mariadb }}
|
||||||
|
@ -1061,7 +1100,7 @@ jobs:
|
||||||
./script/check_dirty
|
./script/check_dirty
|
||||||
|
|
||||||
pytest-postgres:
|
pytest-postgres:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: ${{ matrix.postgresql-group }}
|
image: ${{ matrix.postgresql-group }}
|
||||||
|
@ -1075,6 +1114,7 @@ jobs:
|
||||||
&& github.event.inputs.lint-only != 'true'
|
&& github.event.inputs.lint-only != 'true'
|
||||||
&& github.event.inputs.pylint-only != 'true'
|
&& github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
&& needs.info.outputs.postgresql_groups != '[]'
|
&& needs.info.outputs.postgresql_groups != '[]'
|
||||||
needs:
|
needs:
|
||||||
- info
|
- info
|
||||||
|
@ -1100,19 +1140,21 @@ jobs:
|
||||||
sudo apt-get -y install \
|
sudo apt-get -y install \
|
||||||
bluez \
|
bluez \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
libturbojpeg \
|
libturbojpeg
|
||||||
|
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
|
||||||
|
sudo apt-get -y install \
|
||||||
postgresql-server-dev-14
|
postgresql-server-dev-14
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -1154,7 +1196,8 @@ jobs:
|
||||||
python3 -b -X dev -m pytest \
|
python3 -b -X dev -m pytest \
|
||||||
-qq \
|
-qq \
|
||||||
--timeout=9 \
|
--timeout=9 \
|
||||||
-n 1 \
|
--numprocesses 1 \
|
||||||
|
--snapshot-details \
|
||||||
${cov_params[@]} \
|
${cov_params[@]} \
|
||||||
-o console_output_style=count \
|
-o console_output_style=count \
|
||||||
--durations=0 \
|
--durations=0 \
|
||||||
|
@ -1168,7 +1211,7 @@ jobs:
|
||||||
2>&1 | tee pytest-${{ matrix.python-version }}-${postgresql}.txt
|
2>&1 | tee pytest-${{ matrix.python-version }}-${postgresql}.txt
|
||||||
- name: Upload pytest output
|
- name: Upload pytest output
|
||||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{
|
||||||
steps.pytest-partial.outputs.postgresql }}
|
steps.pytest-partial.outputs.postgresql }}
|
||||||
|
@ -1176,7 +1219,7 @@ jobs:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
if: needs.info.outputs.skip_coverage != 'true'
|
if: needs.info.outputs.skip_coverage != 'true'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.python-version }}-${{
|
name: coverage-${{ matrix.python-version }}-${{
|
||||||
steps.pytest-partial.outputs.postgresql }}
|
steps.pytest-partial.outputs.postgresql }}
|
||||||
|
@ -1198,14 +1241,14 @@ jobs:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Download all coverage artifacts
|
- name: Download all coverage artifacts
|
||||||
uses: actions/download-artifact@v4.1.8
|
uses: actions/download-artifact@v4.1.8
|
||||||
with:
|
with:
|
||||||
pattern: coverage-*
|
pattern: coverage-*
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
if: needs.info.outputs.test_full_suite == 'true'
|
if: needs.info.outputs.test_full_suite == 'true'
|
||||||
uses: codecov/codecov-action@v4.5.0
|
uses: codecov/codecov-action@v4.6.0
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
flags: full-suite
|
flags: full-suite
|
||||||
|
@ -1219,6 +1262,7 @@ jobs:
|
||||||
&& github.event.inputs.lint-only != 'true'
|
&& github.event.inputs.lint-only != 'true'
|
||||||
&& github.event.inputs.pylint-only != 'true'
|
&& github.event.inputs.pylint-only != 'true'
|
||||||
&& github.event.inputs.mypy-only != 'true'
|
&& github.event.inputs.mypy-only != 'true'
|
||||||
|
&& github.event.inputs.audit-licenses-only != 'true'
|
||||||
&& needs.info.outputs.tests_glob
|
&& needs.info.outputs.tests_glob
|
||||||
&& needs.info.outputs.test_full_suite == 'false'
|
&& needs.info.outputs.test_full_suite == 'false'
|
||||||
needs:
|
needs:
|
||||||
|
@ -1248,16 +1292,16 @@ jobs:
|
||||||
libturbojpeg \
|
libturbojpeg \
|
||||||
libgammu-dev
|
libgammu-dev
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
- name: Restore full Python ${{ matrix.python-version }} virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.0.2
|
uses: actions/cache/restore@v4.1.2
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
@ -1299,7 +1343,8 @@ jobs:
|
||||||
python3 -b -X dev -m pytest \
|
python3 -b -X dev -m pytest \
|
||||||
-qq \
|
-qq \
|
||||||
--timeout=9 \
|
--timeout=9 \
|
||||||
-n auto \
|
--numprocesses auto \
|
||||||
|
--snapshot-details \
|
||||||
${cov_params[@]} \
|
${cov_params[@]} \
|
||||||
-o console_output_style=count \
|
-o console_output_style=count \
|
||||||
--durations=0 \
|
--durations=0 \
|
||||||
|
@ -1309,14 +1354,14 @@ jobs:
|
||||||
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
2>&1 | tee pytest-${{ matrix.python-version }}-${{ matrix.group }}.txt
|
||||||
- name: Upload pytest output
|
- name: Upload pytest output
|
||||||
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
if: success() || failure() && steps.pytest-partial.conclusion == 'failure'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
name: pytest-${{ github.run_number }}-${{ matrix.python-version }}-${{ matrix.group }}
|
||||||
path: pytest-*.txt
|
path: pytest-*.txt
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
if: needs.info.outputs.skip_coverage != 'true'
|
if: needs.info.outputs.skip_coverage != 'true'
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
name: coverage-${{ matrix.python-version }}-${{ matrix.group }}
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
@ -1335,14 +1380,14 @@ jobs:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Download all coverage artifacts
|
- name: Download all coverage artifacts
|
||||||
uses: actions/download-artifact@v4.1.8
|
uses: actions/download-artifact@v4.1.8
|
||||||
with:
|
with:
|
||||||
pattern: coverage-*
|
pattern: coverage-*
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
if: needs.info.outputs.test_full_suite == 'false'
|
if: needs.info.outputs.test_full_suite == 'false'
|
||||||
uses: codecov/codecov-action@v4.5.0
|
uses: codecov/codecov-action@v4.6.0
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
|
@ -21,14 +21,14 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3.25.13
|
uses: github/codeql-action/init@v3.27.3
|
||||||
with:
|
with:
|
||||||
languages: python
|
languages: python
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3.25.13
|
uses: github/codeql-action/analyze@v3.27.3
|
||||||
with:
|
with:
|
||||||
category: "/language:python"
|
category: "/language:python"
|
||||||
|
|
4
.github/workflows/translations.yml
vendored
4
.github/workflows/translations.yml
vendored
|
@ -19,10 +19,10 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
|
||||||
|
|
83
.github/workflows/wheels.yml
vendored
83
.github/workflows/wheels.yml
vendored
|
@ -32,11 +32,11 @@ jobs:
|
||||||
architectures: ${{ steps.info.outputs.architectures }}
|
architectures: ${{ steps.info.outputs.architectures }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@v5.1.1
|
uses: actions/setup-python@v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
@ -46,7 +46,7 @@ jobs:
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
python --version
|
python --version
|
||||||
pip install "$(grep '^uv' < requirements_test.txt)"
|
pip install "$(grep '^uv' < requirements.txt)"
|
||||||
uv pip install -r requirements.txt
|
uv pip install -r requirements.txt
|
||||||
|
|
||||||
- name: Get information
|
- name: Get information
|
||||||
|
@ -64,11 +64,8 @@ jobs:
|
||||||
- name: Write env-file
|
- name: Write env-file
|
||||||
run: |
|
run: |
|
||||||
(
|
(
|
||||||
echo "GRPC_BUILD_WITH_BORING_SSL_ASM=false"
|
|
||||||
echo "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=true"
|
echo "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=true"
|
||||||
echo "GRPC_PYTHON_BUILD_WITH_CYTHON=true"
|
echo "GRPC_PYTHON_BUILD_WITH_CYTHON=true"
|
||||||
echo "GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY=true"
|
|
||||||
echo "GRPC_PYTHON_LDFLAGS=-lpthread -Wl,-wrap,memcpy -static-libgcc"
|
|
||||||
|
|
||||||
# Fix out of memory issues with rust
|
# Fix out of memory issues with rust
|
||||||
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
|
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
|
||||||
|
@ -82,14 +79,15 @@ jobs:
|
||||||
) > .env_file
|
) > .env_file
|
||||||
|
|
||||||
- name: Upload env_file
|
- name: Upload env_file
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: env_file
|
name: env_file
|
||||||
path: ./.env_file
|
path: ./.env_file
|
||||||
|
include-hidden-files: true
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
- name: Upload requirements_diff
|
- name: Upload requirements_diff
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: requirements_diff
|
name: requirements_diff
|
||||||
path: ./requirements_diff.txt
|
path: ./requirements_diff.txt
|
||||||
|
@ -101,7 +99,7 @@ jobs:
|
||||||
python -m script.gen_requirements_all ci
|
python -m script.gen_requirements_all ci
|
||||||
|
|
||||||
- name: Upload requirements_all_wheels
|
- name: Upload requirements_all_wheels
|
||||||
uses: actions/upload-artifact@v4.3.4
|
uses: actions/upload-artifact@v4.4.3
|
||||||
with:
|
with:
|
||||||
name: requirements_all_wheels
|
name: requirements_all_wheels
|
||||||
path: ./requirements_all_wheels_*.txt
|
path: ./requirements_all_wheels_*.txt
|
||||||
|
@ -114,11 +112,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
abi: ["cp312"]
|
abi: ["cp312", "cp313"]
|
||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Download env_file
|
- name: Download env_file
|
||||||
uses: actions/download-artifact@v4.1.8
|
uses: actions/download-artifact@v4.1.8
|
||||||
|
@ -130,16 +128,22 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: requirements_diff
|
name: requirements_diff
|
||||||
|
|
||||||
|
- name: Adjust build env
|
||||||
|
run: |
|
||||||
|
# Don't build wheels for uv as uv requires a greater version of rust as currently available on alpine
|
||||||
|
sed -i "/uv/d" requirements.txt
|
||||||
|
sed -i "/uv/d" requirements_diff.txt
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@2024.07.1
|
uses: home-assistant/wheels@2024.11.0
|
||||||
with:
|
with:
|
||||||
abi: ${{ matrix.abi }}
|
abi: ${{ matrix.abi }}
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
env-file: true
|
env-file: true
|
||||||
apk: "libffi-dev;openssl-dev;yaml-dev;nasm"
|
apk: "libffi-dev;openssl-dev;yaml-dev;nasm;zlib-dev"
|
||||||
skip-binary: aiohttp
|
skip-binary: aiohttp;multidict;yarl
|
||||||
constraints: "homeassistant/package_constraints.txt"
|
constraints: "homeassistant/package_constraints.txt"
|
||||||
requirements-diff: "requirements_diff.txt"
|
requirements-diff: "requirements_diff.txt"
|
||||||
requirements: "requirements.txt"
|
requirements: "requirements.txt"
|
||||||
|
@ -152,11 +156,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
abi: ["cp312"]
|
abi: ["cp312", "cp313"]
|
||||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Download env_file
|
- name: Download env_file
|
||||||
uses: actions/download-artifact@v4.1.8
|
uses: actions/download-artifact@v4.1.8
|
||||||
|
@ -173,6 +177,18 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: requirements_all_wheels
|
name: requirements_all_wheels
|
||||||
|
|
||||||
|
- name: Adjust build env
|
||||||
|
run: |
|
||||||
|
if [ "${{ matrix.arch }}" = "i386" ]; then
|
||||||
|
echo "NPY_DISABLE_SVML=1" >> .env_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do not pin numpy in wheels building
|
||||||
|
sed -i "/numpy/d" homeassistant/package_constraints.txt
|
||||||
|
# Don't build wheels for uv as uv requires a greater version of rust as currently available on alpine
|
||||||
|
sed -i "/uv/d" requirements.txt
|
||||||
|
sed -i "/uv/d" requirements_diff.txt
|
||||||
|
|
||||||
- name: Split requirements all
|
- name: Split requirements all
|
||||||
run: |
|
run: |
|
||||||
# We split requirements all into multiple files.
|
# We split requirements all into multiple files.
|
||||||
|
@ -182,28 +198,19 @@ jobs:
|
||||||
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all_wheels_${{ matrix.arch }}.txt requirements_all.txt
|
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all_wheels_${{ matrix.arch }}.txt requirements_all.txt
|
||||||
|
|
||||||
- name: Create requirements for cython<3
|
- name: Create requirements for cython<3
|
||||||
|
if: matrix.abi == 'cp312'
|
||||||
run: |
|
run: |
|
||||||
# Some dependencies still require 'cython<3'
|
# Some dependencies still require 'cython<3'
|
||||||
# and don't yet use isolated build environments.
|
# and don't yet use isolated build environments.
|
||||||
# Build these first.
|
# Build these first.
|
||||||
# grpcio: https://github.com/grpc/grpc/issues/33918
|
|
||||||
# pydantic: https://github.com/pydantic/pydantic/issues/7689
|
# pydantic: https://github.com/pydantic/pydantic/issues/7689
|
||||||
|
|
||||||
touch requirements_old-cython.txt
|
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
|
cat homeassistant/package_constraints.txt | grep 'pydantic==' >> requirements_old-cython.txt
|
||||||
|
|
||||||
- name: Adjust build env
|
|
||||||
run: |
|
|
||||||
if [ "${{ matrix.arch }}" = "i386" ]; then
|
|
||||||
echo "NPY_DISABLE_SVML=1" >> .env_file
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Do not pin numpy in wheels building
|
|
||||||
sed -i "/numpy/d" homeassistant/package_constraints.txt
|
|
||||||
|
|
||||||
- name: Build wheels (old cython)
|
- name: Build wheels (old cython)
|
||||||
uses: home-assistant/wheels@2024.07.1
|
uses: home-assistant/wheels@2024.11.0
|
||||||
|
if: matrix.abi == 'cp312'
|
||||||
with:
|
with:
|
||||||
abi: ${{ matrix.abi }}
|
abi: ${{ matrix.abi }}
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
|
@ -211,50 +218,50 @@ jobs:
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
env-file: true
|
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"
|
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;pydantic
|
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pydantic;pymicro-vad;yarl
|
||||||
constraints: "homeassistant/package_constraints.txt"
|
constraints: "homeassistant/package_constraints.txt"
|
||||||
requirements-diff: "requirements_diff.txt"
|
requirements-diff: "requirements_diff.txt"
|
||||||
requirements: "requirements_old-cython.txt"
|
requirements: "requirements_old-cython.txt"
|
||||||
pip: "'cython<3'"
|
pip: "'cython<3'"
|
||||||
|
|
||||||
- name: Build wheels (part 1)
|
- name: Build wheels (part 1)
|
||||||
uses: home-assistant/wheels@2024.07.1
|
uses: home-assistant/wheels@2024.11.0
|
||||||
with:
|
with:
|
||||||
abi: ${{ matrix.abi }}
|
abi: ${{ matrix.abi }}
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
env-file: true
|
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;nasm"
|
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;nasm;zlib-dev"
|
||||||
skip-binary: aiohttp;charset-normalizer;grpcio;SQLAlchemy;protobuf;pydantic
|
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||||
constraints: "homeassistant/package_constraints.txt"
|
constraints: "homeassistant/package_constraints.txt"
|
||||||
requirements-diff: "requirements_diff.txt"
|
requirements-diff: "requirements_diff.txt"
|
||||||
requirements: "requirements_all.txtaa"
|
requirements: "requirements_all.txtaa"
|
||||||
|
|
||||||
- name: Build wheels (part 2)
|
- name: Build wheels (part 2)
|
||||||
uses: home-assistant/wheels@2024.07.1
|
uses: home-assistant/wheels@2024.11.0
|
||||||
with:
|
with:
|
||||||
abi: ${{ matrix.abi }}
|
abi: ${{ matrix.abi }}
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
env-file: true
|
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;nasm"
|
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;nasm;zlib-dev"
|
||||||
skip-binary: aiohttp;charset-normalizer;grpcio;SQLAlchemy;protobuf;pydantic
|
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||||
constraints: "homeassistant/package_constraints.txt"
|
constraints: "homeassistant/package_constraints.txt"
|
||||||
requirements-diff: "requirements_diff.txt"
|
requirements-diff: "requirements_diff.txt"
|
||||||
requirements: "requirements_all.txtab"
|
requirements: "requirements_all.txtab"
|
||||||
|
|
||||||
- name: Build wheels (part 3)
|
- name: Build wheels (part 3)
|
||||||
uses: home-assistant/wheels@2024.07.1
|
uses: home-assistant/wheels@2024.11.0
|
||||||
with:
|
with:
|
||||||
abi: ${{ matrix.abi }}
|
abi: ${{ matrix.abi }}
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
env-file: true
|
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;nasm"
|
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;nasm;zlib-dev"
|
||||||
skip-binary: aiohttp;charset-normalizer;grpcio;SQLAlchemy;protobuf;pydantic
|
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
|
||||||
constraints: "homeassistant/package_constraints.txt"
|
constraints: "homeassistant/package_constraints.txt"
|
||||||
requirements-diff: "requirements_diff.txt"
|
requirements-diff: "requirements_diff.txt"
|
||||||
requirements: "requirements_all.txtac"
|
requirements: "requirements_all.txtac"
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -79,6 +79,7 @@ pytest-*.txt
|
||||||
.pydevproject
|
.pydevproject
|
||||||
|
|
||||||
.python-version
|
.python-version
|
||||||
|
.tool-versions
|
||||||
|
|
||||||
# emacs auto backups
|
# emacs auto backups
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.5.4
|
rev: v0.7.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args:
|
args:
|
||||||
|
@ -12,7 +12,7 @@ repos:
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell
|
- id: codespell
|
||||||
args:
|
args:
|
||||||
- --ignore-words-list=astroid,checkin,currenty,hass,iif,incomfort,lookin,nam,NotIn,pres,ser,ue
|
- --ignore-words-list=astroid,checkin,currenty,hass,iif,incomfort,lookin,nam,NotIn
|
||||||
- --skip="./.*,*.csv,*.json,*.ambr"
|
- --skip="./.*,*.csv,*.json,*.ambr"
|
||||||
- --quiet-level=2
|
- --quiet-level=2
|
||||||
exclude_types: [csv, json, html]
|
exclude_types: [csv, json, html]
|
||||||
|
@ -83,14 +83,14 @@ repos:
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
language: script
|
language: script
|
||||||
types: [text]
|
types: [text]
|
||||||
files: ^(homeassistant/.+/(icons|manifest|strings)\.json|homeassistant/brands/.*\.json|homeassistant/.+/services\.yaml|script/hassfest/(?!metadata|mypy_config).+\.py|requirements_test.txt)$
|
files: ^(homeassistant/.+/(icons|manifest|strings)\.json|homeassistant/brands/.*\.json|homeassistant/.+/services\.yaml|script/hassfest/(?!metadata|mypy_config).+\.py|requirements.+\.txt)$
|
||||||
- id: hassfest-metadata
|
- id: hassfest-metadata
|
||||||
name: hassfest-metadata
|
name: hassfest-metadata
|
||||||
entry: script/run-in-env.sh python3 -m script.hassfest -p metadata
|
entry: script/run-in-env.sh python3 -m script.hassfest -p metadata,docker
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
language: script
|
language: script
|
||||||
types: [text]
|
types: [text]
|
||||||
files: ^(script/hassfest/metadata\.py|homeassistant/const\.py$|pyproject\.toml)$
|
files: ^(script/hassfest/metadata\.py|homeassistant/const\.py$|pyproject\.toml|homeassistant/components/go2rtc/const\.py)$
|
||||||
- id: hassfest-mypy-config
|
- id: hassfest-mypy-config
|
||||||
name: hassfest-mypy-config
|
name: hassfest-mypy-config
|
||||||
entry: script/run-in-env.sh python3 -m script.hassfest -p mypy_config
|
entry: script/run-in-env.sh python3 -m script.hassfest -p mypy_config
|
||||||
|
|
|
@ -95,8 +95,7 @@ homeassistant.components.aruba.*
|
||||||
homeassistant.components.arwn.*
|
homeassistant.components.arwn.*
|
||||||
homeassistant.components.aseko_pool_live.*
|
homeassistant.components.aseko_pool_live.*
|
||||||
homeassistant.components.assist_pipeline.*
|
homeassistant.components.assist_pipeline.*
|
||||||
homeassistant.components.asterisk_cdr.*
|
homeassistant.components.assist_satellite.*
|
||||||
homeassistant.components.asterisk_mbox.*
|
|
||||||
homeassistant.components.asuswrt.*
|
homeassistant.components.asuswrt.*
|
||||||
homeassistant.components.autarco.*
|
homeassistant.components.autarco.*
|
||||||
homeassistant.components.auth.*
|
homeassistant.components.auth.*
|
||||||
|
@ -112,6 +111,7 @@ homeassistant.components.bitcoin.*
|
||||||
homeassistant.components.blockchain.*
|
homeassistant.components.blockchain.*
|
||||||
homeassistant.components.blue_current.*
|
homeassistant.components.blue_current.*
|
||||||
homeassistant.components.blueprint.*
|
homeassistant.components.blueprint.*
|
||||||
|
homeassistant.components.bluesound.*
|
||||||
homeassistant.components.bluetooth.*
|
homeassistant.components.bluetooth.*
|
||||||
homeassistant.components.bluetooth_adapters.*
|
homeassistant.components.bluetooth_adapters.*
|
||||||
homeassistant.components.bluetooth_tracker.*
|
homeassistant.components.bluetooth_tracker.*
|
||||||
|
@ -120,9 +120,11 @@ homeassistant.components.bond.*
|
||||||
homeassistant.components.braviatv.*
|
homeassistant.components.braviatv.*
|
||||||
homeassistant.components.brother.*
|
homeassistant.components.brother.*
|
||||||
homeassistant.components.browser.*
|
homeassistant.components.browser.*
|
||||||
|
homeassistant.components.bryant_evolution.*
|
||||||
homeassistant.components.bthome.*
|
homeassistant.components.bthome.*
|
||||||
homeassistant.components.button.*
|
homeassistant.components.button.*
|
||||||
homeassistant.components.calendar.*
|
homeassistant.components.calendar.*
|
||||||
|
homeassistant.components.cambridge_audio.*
|
||||||
homeassistant.components.camera.*
|
homeassistant.components.camera.*
|
||||||
homeassistant.components.canary.*
|
homeassistant.components.canary.*
|
||||||
homeassistant.components.cert_expiry.*
|
homeassistant.components.cert_expiry.*
|
||||||
|
@ -140,6 +142,7 @@ homeassistant.components.cpuspeed.*
|
||||||
homeassistant.components.crownstone.*
|
homeassistant.components.crownstone.*
|
||||||
homeassistant.components.date.*
|
homeassistant.components.date.*
|
||||||
homeassistant.components.datetime.*
|
homeassistant.components.datetime.*
|
||||||
|
homeassistant.components.deako.*
|
||||||
homeassistant.components.deconz.*
|
homeassistant.components.deconz.*
|
||||||
homeassistant.components.default_config.*
|
homeassistant.components.default_config.*
|
||||||
homeassistant.components.demo.*
|
homeassistant.components.demo.*
|
||||||
|
@ -167,6 +170,7 @@ homeassistant.components.ecowitt.*
|
||||||
homeassistant.components.efergy.*
|
homeassistant.components.efergy.*
|
||||||
homeassistant.components.electrasmart.*
|
homeassistant.components.electrasmart.*
|
||||||
homeassistant.components.electric_kiwi.*
|
homeassistant.components.electric_kiwi.*
|
||||||
|
homeassistant.components.elevenlabs.*
|
||||||
homeassistant.components.elgato.*
|
homeassistant.components.elgato.*
|
||||||
homeassistant.components.elkm1.*
|
homeassistant.components.elkm1.*
|
||||||
homeassistant.components.emulated_hue.*
|
homeassistant.components.emulated_hue.*
|
||||||
|
@ -196,17 +200,23 @@ homeassistant.components.fritzbox.*
|
||||||
homeassistant.components.fritzbox_callmonitor.*
|
homeassistant.components.fritzbox_callmonitor.*
|
||||||
homeassistant.components.fronius.*
|
homeassistant.components.fronius.*
|
||||||
homeassistant.components.frontend.*
|
homeassistant.components.frontend.*
|
||||||
|
homeassistant.components.fujitsu_fglair.*
|
||||||
homeassistant.components.fully_kiosk.*
|
homeassistant.components.fully_kiosk.*
|
||||||
|
homeassistant.components.fyta.*
|
||||||
homeassistant.components.generic_hygrostat.*
|
homeassistant.components.generic_hygrostat.*
|
||||||
homeassistant.components.generic_thermostat.*
|
homeassistant.components.generic_thermostat.*
|
||||||
homeassistant.components.geo_location.*
|
homeassistant.components.geo_location.*
|
||||||
homeassistant.components.geocaching.*
|
homeassistant.components.geocaching.*
|
||||||
homeassistant.components.gios.*
|
homeassistant.components.gios.*
|
||||||
homeassistant.components.glances.*
|
homeassistant.components.glances.*
|
||||||
|
homeassistant.components.go2rtc.*
|
||||||
homeassistant.components.goalzero.*
|
homeassistant.components.goalzero.*
|
||||||
homeassistant.components.google.*
|
homeassistant.components.google.*
|
||||||
homeassistant.components.google_assistant_sdk.*
|
homeassistant.components.google_assistant_sdk.*
|
||||||
|
homeassistant.components.google_cloud.*
|
||||||
|
homeassistant.components.google_photos.*
|
||||||
homeassistant.components.google_sheets.*
|
homeassistant.components.google_sheets.*
|
||||||
|
homeassistant.components.govee_ble.*
|
||||||
homeassistant.components.gpsd.*
|
homeassistant.components.gpsd.*
|
||||||
homeassistant.components.greeneye_monitor.*
|
homeassistant.components.greeneye_monitor.*
|
||||||
homeassistant.components.group.*
|
homeassistant.components.group.*
|
||||||
|
@ -276,6 +286,7 @@ homeassistant.components.lawn_mower.*
|
||||||
homeassistant.components.lcn.*
|
homeassistant.components.lcn.*
|
||||||
homeassistant.components.ld2410_ble.*
|
homeassistant.components.ld2410_ble.*
|
||||||
homeassistant.components.led_ble.*
|
homeassistant.components.led_ble.*
|
||||||
|
homeassistant.components.lektrico.*
|
||||||
homeassistant.components.lidarr.*
|
homeassistant.components.lidarr.*
|
||||||
homeassistant.components.lifx.*
|
homeassistant.components.lifx.*
|
||||||
homeassistant.components.light.*
|
homeassistant.components.light.*
|
||||||
|
@ -292,8 +303,7 @@ homeassistant.components.london_underground.*
|
||||||
homeassistant.components.lookin.*
|
homeassistant.components.lookin.*
|
||||||
homeassistant.components.luftdaten.*
|
homeassistant.components.luftdaten.*
|
||||||
homeassistant.components.madvr.*
|
homeassistant.components.madvr.*
|
||||||
homeassistant.components.mailbox.*
|
homeassistant.components.manual.*
|
||||||
homeassistant.components.map.*
|
|
||||||
homeassistant.components.mastodon.*
|
homeassistant.components.mastodon.*
|
||||||
homeassistant.components.matrix.*
|
homeassistant.components.matrix.*
|
||||||
homeassistant.components.matter.*
|
homeassistant.components.matter.*
|
||||||
|
@ -308,16 +318,19 @@ homeassistant.components.minecraft_server.*
|
||||||
homeassistant.components.mjpeg.*
|
homeassistant.components.mjpeg.*
|
||||||
homeassistant.components.modbus.*
|
homeassistant.components.modbus.*
|
||||||
homeassistant.components.modem_callerid.*
|
homeassistant.components.modem_callerid.*
|
||||||
|
homeassistant.components.mold_indicator.*
|
||||||
homeassistant.components.monzo.*
|
homeassistant.components.monzo.*
|
||||||
homeassistant.components.moon.*
|
homeassistant.components.moon.*
|
||||||
homeassistant.components.mopeka.*
|
homeassistant.components.mopeka.*
|
||||||
homeassistant.components.motionmount.*
|
homeassistant.components.motionmount.*
|
||||||
homeassistant.components.mqtt.*
|
homeassistant.components.mqtt.*
|
||||||
|
homeassistant.components.music_assistant.*
|
||||||
homeassistant.components.my.*
|
homeassistant.components.my.*
|
||||||
homeassistant.components.mysensors.*
|
homeassistant.components.mysensors.*
|
||||||
homeassistant.components.myuplink.*
|
homeassistant.components.myuplink.*
|
||||||
homeassistant.components.nam.*
|
homeassistant.components.nam.*
|
||||||
homeassistant.components.nanoleaf.*
|
homeassistant.components.nanoleaf.*
|
||||||
|
homeassistant.components.nasweb.*
|
||||||
homeassistant.components.neato.*
|
homeassistant.components.neato.*
|
||||||
homeassistant.components.nest.*
|
homeassistant.components.nest.*
|
||||||
homeassistant.components.netatmo.*
|
homeassistant.components.netatmo.*
|
||||||
|
@ -327,6 +340,7 @@ homeassistant.components.nfandroidtv.*
|
||||||
homeassistant.components.nightscout.*
|
homeassistant.components.nightscout.*
|
||||||
homeassistant.components.nissan_leaf.*
|
homeassistant.components.nissan_leaf.*
|
||||||
homeassistant.components.no_ip.*
|
homeassistant.components.no_ip.*
|
||||||
|
homeassistant.components.nordpool.*
|
||||||
homeassistant.components.notify.*
|
homeassistant.components.notify.*
|
||||||
homeassistant.components.notion.*
|
homeassistant.components.notion.*
|
||||||
homeassistant.components.number.*
|
homeassistant.components.number.*
|
||||||
|
@ -334,7 +348,9 @@ homeassistant.components.nut.*
|
||||||
homeassistant.components.onboarding.*
|
homeassistant.components.onboarding.*
|
||||||
homeassistant.components.oncue.*
|
homeassistant.components.oncue.*
|
||||||
homeassistant.components.onewire.*
|
homeassistant.components.onewire.*
|
||||||
|
homeassistant.components.onkyo.*
|
||||||
homeassistant.components.open_meteo.*
|
homeassistant.components.open_meteo.*
|
||||||
|
homeassistant.components.openai_conversation.*
|
||||||
homeassistant.components.openexchangerates.*
|
homeassistant.components.openexchangerates.*
|
||||||
homeassistant.components.opensky.*
|
homeassistant.components.opensky.*
|
||||||
homeassistant.components.openuv.*
|
homeassistant.components.openuv.*
|
||||||
|
@ -342,6 +358,7 @@ homeassistant.components.oralb.*
|
||||||
homeassistant.components.otbr.*
|
homeassistant.components.otbr.*
|
||||||
homeassistant.components.overkiz.*
|
homeassistant.components.overkiz.*
|
||||||
homeassistant.components.p1_monitor.*
|
homeassistant.components.p1_monitor.*
|
||||||
|
homeassistant.components.panel_custom.*
|
||||||
homeassistant.components.peco.*
|
homeassistant.components.peco.*
|
||||||
homeassistant.components.persistent_notification.*
|
homeassistant.components.persistent_notification.*
|
||||||
homeassistant.components.pi_hole.*
|
homeassistant.components.pi_hole.*
|
||||||
|
@ -359,6 +376,7 @@ homeassistant.components.pvoutput.*
|
||||||
homeassistant.components.qnap_qsw.*
|
homeassistant.components.qnap_qsw.*
|
||||||
homeassistant.components.rabbitair.*
|
homeassistant.components.rabbitair.*
|
||||||
homeassistant.components.radarr.*
|
homeassistant.components.radarr.*
|
||||||
|
homeassistant.components.radio_browser.*
|
||||||
homeassistant.components.rainforest_raven.*
|
homeassistant.components.rainforest_raven.*
|
||||||
homeassistant.components.rainmachine.*
|
homeassistant.components.rainmachine.*
|
||||||
homeassistant.components.raspberry_pi.*
|
homeassistant.components.raspberry_pi.*
|
||||||
|
@ -393,8 +411,10 @@ homeassistant.components.select.*
|
||||||
homeassistant.components.sensibo.*
|
homeassistant.components.sensibo.*
|
||||||
homeassistant.components.sensirion_ble.*
|
homeassistant.components.sensirion_ble.*
|
||||||
homeassistant.components.sensor.*
|
homeassistant.components.sensor.*
|
||||||
|
homeassistant.components.sensoterra.*
|
||||||
homeassistant.components.senz.*
|
homeassistant.components.senz.*
|
||||||
homeassistant.components.sfr_box.*
|
homeassistant.components.sfr_box.*
|
||||||
|
homeassistant.components.shell_command.*
|
||||||
homeassistant.components.shelly.*
|
homeassistant.components.shelly.*
|
||||||
homeassistant.components.shopping_list.*
|
homeassistant.components.shopping_list.*
|
||||||
homeassistant.components.simplepush.*
|
homeassistant.components.simplepush.*
|
||||||
|
@ -404,10 +424,14 @@ homeassistant.components.skybell.*
|
||||||
homeassistant.components.slack.*
|
homeassistant.components.slack.*
|
||||||
homeassistant.components.sleepiq.*
|
homeassistant.components.sleepiq.*
|
||||||
homeassistant.components.smhi.*
|
homeassistant.components.smhi.*
|
||||||
|
homeassistant.components.smlight.*
|
||||||
homeassistant.components.snooz.*
|
homeassistant.components.snooz.*
|
||||||
|
homeassistant.components.solarlog.*
|
||||||
homeassistant.components.sonarr.*
|
homeassistant.components.sonarr.*
|
||||||
homeassistant.components.speedtestdotnet.*
|
homeassistant.components.speedtestdotnet.*
|
||||||
|
homeassistant.components.spotify.*
|
||||||
homeassistant.components.sql.*
|
homeassistant.components.sql.*
|
||||||
|
homeassistant.components.squeezebox.*
|
||||||
homeassistant.components.ssdp.*
|
homeassistant.components.ssdp.*
|
||||||
homeassistant.components.starlink.*
|
homeassistant.components.starlink.*
|
||||||
homeassistant.components.statistics.*
|
homeassistant.components.statistics.*
|
||||||
|
@ -420,6 +444,7 @@ homeassistant.components.suez_water.*
|
||||||
homeassistant.components.sun.*
|
homeassistant.components.sun.*
|
||||||
homeassistant.components.surepetcare.*
|
homeassistant.components.surepetcare.*
|
||||||
homeassistant.components.switch.*
|
homeassistant.components.switch.*
|
||||||
|
homeassistant.components.switch_as_x.*
|
||||||
homeassistant.components.switchbee.*
|
homeassistant.components.switchbee.*
|
||||||
homeassistant.components.switchbot_cloud.*
|
homeassistant.components.switchbot_cloud.*
|
||||||
homeassistant.components.switcher_kis.*
|
homeassistant.components.switcher_kis.*
|
||||||
|
@ -467,6 +492,7 @@ homeassistant.components.update.*
|
||||||
homeassistant.components.uptime.*
|
homeassistant.components.uptime.*
|
||||||
homeassistant.components.uptimerobot.*
|
homeassistant.components.uptimerobot.*
|
||||||
homeassistant.components.usb.*
|
homeassistant.components.usb.*
|
||||||
|
homeassistant.components.uvc.*
|
||||||
homeassistant.components.vacuum.*
|
homeassistant.components.vacuum.*
|
||||||
homeassistant.components.vallox.*
|
homeassistant.components.vallox.*
|
||||||
homeassistant.components.valve.*
|
homeassistant.components.valve.*
|
||||||
|
@ -487,6 +513,7 @@ homeassistant.components.whois.*
|
||||||
homeassistant.components.withings.*
|
homeassistant.components.withings.*
|
||||||
homeassistant.components.wiz.*
|
homeassistant.components.wiz.*
|
||||||
homeassistant.components.wled.*
|
homeassistant.components.wled.*
|
||||||
|
homeassistant.components.workday.*
|
||||||
homeassistant.components.worldclock.*
|
homeassistant.components.worldclock.*
|
||||||
homeassistant.components.xiaomi_ble.*
|
homeassistant.components.xiaomi_ble.*
|
||||||
homeassistant.components.yale_smart_alarm.*
|
homeassistant.components.yale_smart_alarm.*
|
||||||
|
|
10
.vscode/settings.default.json
vendored
10
.vscode/settings.default.json
vendored
|
@ -6,5 +6,13 @@
|
||||||
// https://code.visualstudio.com/docs/python/testing#_pytest-configuration-settings
|
// https://code.visualstudio.com/docs/python/testing#_pytest-configuration-settings
|
||||||
"python.testing.pytestEnabled": false,
|
"python.testing.pytestEnabled": false,
|
||||||
// https://code.visualstudio.com/docs/python/linting#_general-settings
|
// https://code.visualstudio.com/docs/python/linting#_general-settings
|
||||||
"pylint.importStrategy": "fromEnvironment"
|
"pylint.importStrategy": "fromEnvironment",
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": [
|
||||||
|
"homeassistant/components/*/manifest.json"
|
||||||
|
],
|
||||||
|
"url": "./script/json_schemas/manifest_schema.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
141
CODEOWNERS
141
CODEOWNERS
|
@ -40,6 +40,8 @@ build.json @home-assistant/supervisor
|
||||||
# Integrations
|
# Integrations
|
||||||
/homeassistant/components/abode/ @shred86
|
/homeassistant/components/abode/ @shred86
|
||||||
/tests/components/abode/ @shred86
|
/tests/components/abode/ @shred86
|
||||||
|
/homeassistant/components/acaia/ @zweckj
|
||||||
|
/tests/components/acaia/ @zweckj
|
||||||
/homeassistant/components/accuweather/ @bieniu
|
/homeassistant/components/accuweather/ @bieniu
|
||||||
/tests/components/accuweather/ @bieniu
|
/tests/components/accuweather/ @bieniu
|
||||||
/homeassistant/components/acmeda/ @atmurray
|
/homeassistant/components/acmeda/ @atmurray
|
||||||
|
@ -48,6 +50,7 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/adax/ @danielhiversen
|
/tests/components/adax/ @danielhiversen
|
||||||
/homeassistant/components/adguard/ @frenck
|
/homeassistant/components/adguard/ @frenck
|
||||||
/tests/components/adguard/ @frenck
|
/tests/components/adguard/ @frenck
|
||||||
|
/homeassistant/components/ads/ @mrpasztoradam
|
||||||
/homeassistant/components/advantage_air/ @Bre77
|
/homeassistant/components/advantage_air/ @Bre77
|
||||||
/tests/components/advantage_air/ @Bre77
|
/tests/components/advantage_air/ @Bre77
|
||||||
/homeassistant/components/aemet/ @Noltari
|
/homeassistant/components/aemet/ @Noltari
|
||||||
|
@ -108,6 +111,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/anova/ @Lash-L
|
/tests/components/anova/ @Lash-L
|
||||||
/homeassistant/components/anthemav/ @hyralex
|
/homeassistant/components/anthemav/ @hyralex
|
||||||
/tests/components/anthemav/ @hyralex
|
/tests/components/anthemav/ @hyralex
|
||||||
|
/homeassistant/components/anthropic/ @Shulyaka
|
||||||
|
/tests/components/anthropic/ @Shulyaka
|
||||||
/homeassistant/components/aosmith/ @bdr99
|
/homeassistant/components/aosmith/ @bdr99
|
||||||
/tests/components/aosmith/ @bdr99
|
/tests/components/aosmith/ @bdr99
|
||||||
/homeassistant/components/apache_kafka/ @bachya
|
/homeassistant/components/apache_kafka/ @bachya
|
||||||
|
@ -141,6 +146,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/aseko_pool_live/ @milanmeu
|
/tests/components/aseko_pool_live/ @milanmeu
|
||||||
/homeassistant/components/assist_pipeline/ @balloob @synesthesiam
|
/homeassistant/components/assist_pipeline/ @balloob @synesthesiam
|
||||||
/tests/components/assist_pipeline/ @balloob @synesthesiam
|
/tests/components/assist_pipeline/ @balloob @synesthesiam
|
||||||
|
/homeassistant/components/assist_satellite/ @home-assistant/core @synesthesiam
|
||||||
|
/tests/components/assist_satellite/ @home-assistant/core @synesthesiam
|
||||||
/homeassistant/components/asuswrt/ @kennedyshead @ollo69
|
/homeassistant/components/asuswrt/ @kennedyshead @ollo69
|
||||||
/tests/components/asuswrt/ @kennedyshead @ollo69
|
/tests/components/asuswrt/ @kennedyshead @ollo69
|
||||||
/homeassistant/components/atag/ @MatsNL
|
/homeassistant/components/atag/ @MatsNL
|
||||||
|
@ -197,7 +204,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/bluemaestro/ @bdraco
|
/tests/components/bluemaestro/ @bdraco
|
||||||
/homeassistant/components/blueprint/ @home-assistant/core
|
/homeassistant/components/blueprint/ @home-assistant/core
|
||||||
/tests/components/blueprint/ @home-assistant/core
|
/tests/components/blueprint/ @home-assistant/core
|
||||||
/homeassistant/components/bluesound/ @thrawnarn
|
/homeassistant/components/bluesound/ @thrawnarn @LouisChrist
|
||||||
|
/tests/components/bluesound/ @thrawnarn @LouisChrist
|
||||||
/homeassistant/components/bluetooth/ @bdraco
|
/homeassistant/components/bluetooth/ @bdraco
|
||||||
/tests/components/bluetooth/ @bdraco
|
/tests/components/bluetooth/ @bdraco
|
||||||
/homeassistant/components/bluetooth_adapters/ @bdraco
|
/homeassistant/components/bluetooth_adapters/ @bdraco
|
||||||
|
@ -220,17 +228,21 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/brottsplatskartan/ @gjohansson-ST
|
/tests/components/brottsplatskartan/ @gjohansson-ST
|
||||||
/homeassistant/components/brunt/ @eavanvalkenburg
|
/homeassistant/components/brunt/ @eavanvalkenburg
|
||||||
/tests/components/brunt/ @eavanvalkenburg
|
/tests/components/brunt/ @eavanvalkenburg
|
||||||
|
/homeassistant/components/bryant_evolution/ @danielsmyers
|
||||||
|
/tests/components/bryant_evolution/ @danielsmyers
|
||||||
/homeassistant/components/bsblan/ @liudger
|
/homeassistant/components/bsblan/ @liudger
|
||||||
/tests/components/bsblan/ @liudger
|
/tests/components/bsblan/ @liudger
|
||||||
/homeassistant/components/bt_smarthub/ @typhoon2099
|
/homeassistant/components/bt_smarthub/ @typhoon2099
|
||||||
/homeassistant/components/bthome/ @Ernst79
|
/homeassistant/components/bthome/ @Ernst79 @thecode
|
||||||
/tests/components/bthome/ @Ernst79
|
/tests/components/bthome/ @Ernst79 @thecode
|
||||||
/homeassistant/components/buienradar/ @mjj4791 @ties @Robbie1221
|
/homeassistant/components/buienradar/ @mjj4791 @ties @Robbie1221
|
||||||
/tests/components/buienradar/ @mjj4791 @ties @Robbie1221
|
/tests/components/buienradar/ @mjj4791 @ties @Robbie1221
|
||||||
/homeassistant/components/button/ @home-assistant/core
|
/homeassistant/components/button/ @home-assistant/core
|
||||||
/tests/components/button/ @home-assistant/core
|
/tests/components/button/ @home-assistant/core
|
||||||
/homeassistant/components/calendar/ @home-assistant/core
|
/homeassistant/components/calendar/ @home-assistant/core
|
||||||
/tests/components/calendar/ @home-assistant/core
|
/tests/components/calendar/ @home-assistant/core
|
||||||
|
/homeassistant/components/cambridge_audio/ @noahhusby
|
||||||
|
/tests/components/cambridge_audio/ @noahhusby
|
||||||
/homeassistant/components/camera/ @home-assistant/core
|
/homeassistant/components/camera/ @home-assistant/core
|
||||||
/tests/components/camera/ @home-assistant/core
|
/tests/components/camera/ @home-assistant/core
|
||||||
/homeassistant/components/cast/ @emontnemery
|
/homeassistant/components/cast/ @emontnemery
|
||||||
|
@ -289,6 +301,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/date/ @home-assistant/core
|
/tests/components/date/ @home-assistant/core
|
||||||
/homeassistant/components/datetime/ @home-assistant/core
|
/homeassistant/components/datetime/ @home-assistant/core
|
||||||
/tests/components/datetime/ @home-assistant/core
|
/tests/components/datetime/ @home-assistant/core
|
||||||
|
/homeassistant/components/deako/ @sebirdman @balake @deakolights
|
||||||
|
/tests/components/deako/ @sebirdman @balake @deakolights
|
||||||
/homeassistant/components/debugpy/ @frenck
|
/homeassistant/components/debugpy/ @frenck
|
||||||
/tests/components/debugpy/ @frenck
|
/tests/components/debugpy/ @frenck
|
||||||
/homeassistant/components/deconz/ @Kane610
|
/homeassistant/components/deconz/ @Kane610
|
||||||
|
@ -344,10 +358,12 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/dremel_3d_printer/ @tkdrob
|
/tests/components/dremel_3d_printer/ @tkdrob
|
||||||
/homeassistant/components/drop_connect/ @ChandlerSystems @pfrazer
|
/homeassistant/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||||
/tests/components/drop_connect/ @ChandlerSystems @pfrazer
|
/tests/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||||
/homeassistant/components/dsmr/ @Robbie1221 @frenck
|
/homeassistant/components/dsmr/ @Robbie1221
|
||||||
/tests/components/dsmr/ @Robbie1221 @frenck
|
/tests/components/dsmr/ @Robbie1221
|
||||||
/homeassistant/components/dsmr_reader/ @sorted-bits @glodenox @erwindouna
|
/homeassistant/components/dsmr_reader/ @sorted-bits @glodenox @erwindouna
|
||||||
/tests/components/dsmr_reader/ @sorted-bits @glodenox @erwindouna
|
/tests/components/dsmr_reader/ @sorted-bits @glodenox @erwindouna
|
||||||
|
/homeassistant/components/duke_energy/ @hunterjm
|
||||||
|
/tests/components/duke_energy/ @hunterjm
|
||||||
/homeassistant/components/duotecno/ @cereal2nd
|
/homeassistant/components/duotecno/ @cereal2nd
|
||||||
/tests/components/duotecno/ @cereal2nd
|
/tests/components/duotecno/ @cereal2nd
|
||||||
/homeassistant/components/dwd_weather_warnings/ @runningman84 @stephan192 @andarotajo
|
/homeassistant/components/dwd_weather_warnings/ @runningman84 @stephan192 @andarotajo
|
||||||
|
@ -373,6 +389,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/electrasmart/ @jafar-atili
|
/tests/components/electrasmart/ @jafar-atili
|
||||||
/homeassistant/components/electric_kiwi/ @mikey0000
|
/homeassistant/components/electric_kiwi/ @mikey0000
|
||||||
/tests/components/electric_kiwi/ @mikey0000
|
/tests/components/electric_kiwi/ @mikey0000
|
||||||
|
/homeassistant/components/elevenlabs/ @sorgfresser
|
||||||
|
/tests/components/elevenlabs/ @sorgfresser
|
||||||
/homeassistant/components/elgato/ @frenck
|
/homeassistant/components/elgato/ @frenck
|
||||||
/tests/components/elgato/ @frenck
|
/tests/components/elgato/ @frenck
|
||||||
/homeassistant/components/elkm1/ @gwww @bdraco
|
/homeassistant/components/elkm1/ @gwww @bdraco
|
||||||
|
@ -426,6 +444,7 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/evil_genius_labs/ @balloob
|
/homeassistant/components/evil_genius_labs/ @balloob
|
||||||
/tests/components/evil_genius_labs/ @balloob
|
/tests/components/evil_genius_labs/ @balloob
|
||||||
/homeassistant/components/evohome/ @zxdavb
|
/homeassistant/components/evohome/ @zxdavb
|
||||||
|
/tests/components/evohome/ @zxdavb
|
||||||
/homeassistant/components/ezviz/ @RenierM26 @baqs
|
/homeassistant/components/ezviz/ @RenierM26 @baqs
|
||||||
/tests/components/ezviz/ @RenierM26 @baqs
|
/tests/components/ezviz/ @RenierM26 @baqs
|
||||||
/homeassistant/components/faa_delays/ @ntilley905
|
/homeassistant/components/faa_delays/ @ntilley905
|
||||||
|
@ -479,8 +498,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/freebox/ @hacf-fr @Quentame
|
/tests/components/freebox/ @hacf-fr @Quentame
|
||||||
/homeassistant/components/freedompro/ @stefano055415
|
/homeassistant/components/freedompro/ @stefano055415
|
||||||
/tests/components/freedompro/ @stefano055415
|
/tests/components/freedompro/ @stefano055415
|
||||||
/homeassistant/components/fritz/ @mammuth @AaronDavidSchneider @chemelli74 @mib1185
|
/homeassistant/components/fritz/ @AaronDavidSchneider @chemelli74 @mib1185
|
||||||
/tests/components/fritz/ @mammuth @AaronDavidSchneider @chemelli74 @mib1185
|
/tests/components/fritz/ @AaronDavidSchneider @chemelli74 @mib1185
|
||||||
/homeassistant/components/fritzbox/ @mib1185 @flabbamann
|
/homeassistant/components/fritzbox/ @mib1185 @flabbamann
|
||||||
/tests/components/fritzbox/ @mib1185 @flabbamann
|
/tests/components/fritzbox/ @mib1185 @flabbamann
|
||||||
/homeassistant/components/fritzbox_callmonitor/ @cdce8p
|
/homeassistant/components/fritzbox_callmonitor/ @cdce8p
|
||||||
|
@ -491,6 +510,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/frontend/ @home-assistant/frontend
|
/tests/components/frontend/ @home-assistant/frontend
|
||||||
/homeassistant/components/frontier_silicon/ @wlcrs
|
/homeassistant/components/frontier_silicon/ @wlcrs
|
||||||
/tests/components/frontier_silicon/ @wlcrs
|
/tests/components/frontier_silicon/ @wlcrs
|
||||||
|
/homeassistant/components/fujitsu_fglair/ @crevetor
|
||||||
|
/tests/components/fujitsu_fglair/ @crevetor
|
||||||
/homeassistant/components/fully_kiosk/ @cgarwood
|
/homeassistant/components/fully_kiosk/ @cgarwood
|
||||||
/tests/components/fully_kiosk/ @cgarwood
|
/tests/components/fully_kiosk/ @cgarwood
|
||||||
/homeassistant/components/fyta/ @dontinelli
|
/homeassistant/components/fyta/ @dontinelli
|
||||||
|
@ -525,6 +546,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/github/ @timmo001 @ludeeus
|
/tests/components/github/ @timmo001 @ludeeus
|
||||||
/homeassistant/components/glances/ @engrbm87
|
/homeassistant/components/glances/ @engrbm87
|
||||||
/tests/components/glances/ @engrbm87
|
/tests/components/glances/ @engrbm87
|
||||||
|
/homeassistant/components/go2rtc/ @home-assistant/core
|
||||||
|
/tests/components/go2rtc/ @home-assistant/core
|
||||||
/homeassistant/components/goalzero/ @tkdrob
|
/homeassistant/components/goalzero/ @tkdrob
|
||||||
/tests/components/goalzero/ @tkdrob
|
/tests/components/goalzero/ @tkdrob
|
||||||
/homeassistant/components/gogogate2/ @vangorra
|
/homeassistant/components/gogogate2/ @vangorra
|
||||||
|
@ -537,11 +560,14 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/google_assistant/ @home-assistant/cloud
|
/tests/components/google_assistant/ @home-assistant/cloud
|
||||||
/homeassistant/components/google_assistant_sdk/ @tronikos
|
/homeassistant/components/google_assistant_sdk/ @tronikos
|
||||||
/tests/components/google_assistant_sdk/ @tronikos
|
/tests/components/google_assistant_sdk/ @tronikos
|
||||||
/homeassistant/components/google_cloud/ @lufton
|
/homeassistant/components/google_cloud/ @lufton @tronikos
|
||||||
|
/tests/components/google_cloud/ @lufton @tronikos
|
||||||
/homeassistant/components/google_generative_ai_conversation/ @tronikos
|
/homeassistant/components/google_generative_ai_conversation/ @tronikos
|
||||||
/tests/components/google_generative_ai_conversation/ @tronikos
|
/tests/components/google_generative_ai_conversation/ @tronikos
|
||||||
/homeassistant/components/google_mail/ @tkdrob
|
/homeassistant/components/google_mail/ @tkdrob
|
||||||
/tests/components/google_mail/ @tkdrob
|
/tests/components/google_mail/ @tkdrob
|
||||||
|
/homeassistant/components/google_photos/ @allenporter
|
||||||
|
/tests/components/google_photos/ @allenporter
|
||||||
/homeassistant/components/google_sheets/ @tkdrob
|
/homeassistant/components/google_sheets/ @tkdrob
|
||||||
/tests/components/google_sheets/ @tkdrob
|
/tests/components/google_sheets/ @tkdrob
|
||||||
/homeassistant/components/google_tasks/ @allenporter
|
/homeassistant/components/google_tasks/ @allenporter
|
||||||
|
@ -593,8 +619,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/hlk_sw16/ @jameshilliard
|
/tests/components/hlk_sw16/ @jameshilliard
|
||||||
/homeassistant/components/holiday/ @jrieger @gjohansson-ST
|
/homeassistant/components/holiday/ @jrieger @gjohansson-ST
|
||||||
/tests/components/holiday/ @jrieger @gjohansson-ST
|
/tests/components/holiday/ @jrieger @gjohansson-ST
|
||||||
/homeassistant/components/home_connect/ @DavidMStraub
|
/homeassistant/components/home_connect/ @DavidMStraub @Diegorro98
|
||||||
/tests/components/home_connect/ @DavidMStraub
|
/tests/components/home_connect/ @DavidMStraub @Diegorro98
|
||||||
/homeassistant/components/homeassistant/ @home-assistant/core
|
/homeassistant/components/homeassistant/ @home-assistant/core
|
||||||
/tests/components/homeassistant/ @home-assistant/core
|
/tests/components/homeassistant/ @home-assistant/core
|
||||||
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
|
/homeassistant/components/homeassistant_alerts/ @home-assistant/core
|
||||||
|
@ -619,6 +645,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/homewizard/ @DCSBL
|
/tests/components/homewizard/ @DCSBL
|
||||||
/homeassistant/components/honeywell/ @rdfurman @mkmer
|
/homeassistant/components/honeywell/ @rdfurman @mkmer
|
||||||
/tests/components/honeywell/ @rdfurman @mkmer
|
/tests/components/honeywell/ @rdfurman @mkmer
|
||||||
|
/homeassistant/components/html5/ @alexyao2015
|
||||||
|
/tests/components/html5/ @alexyao2015
|
||||||
/homeassistant/components/http/ @home-assistant/core
|
/homeassistant/components/http/ @home-assistant/core
|
||||||
/tests/components/http/ @home-assistant/core
|
/tests/components/http/ @home-assistant/core
|
||||||
/homeassistant/components/huawei_lte/ @scop @fphammerle
|
/homeassistant/components/huawei_lte/ @scop @fphammerle
|
||||||
|
@ -633,6 +661,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/hunterdouglas_powerview/ @bdraco @kingy444 @trullock
|
/tests/components/hunterdouglas_powerview/ @bdraco @kingy444 @trullock
|
||||||
/homeassistant/components/husqvarna_automower/ @Thomas55555
|
/homeassistant/components/husqvarna_automower/ @Thomas55555
|
||||||
/tests/components/husqvarna_automower/ @Thomas55555
|
/tests/components/husqvarna_automower/ @Thomas55555
|
||||||
|
/homeassistant/components/husqvarna_automower_ble/ @alistair23
|
||||||
|
/tests/components/husqvarna_automower_ble/ @alistair23
|
||||||
/homeassistant/components/huum/ @frwickst
|
/homeassistant/components/huum/ @frwickst
|
||||||
/tests/components/huum/ @frwickst
|
/tests/components/huum/ @frwickst
|
||||||
/homeassistant/components/hvv_departures/ @vigonotion
|
/homeassistant/components/hvv_departures/ @vigonotion
|
||||||
|
@ -697,8 +727,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/ios/ @robbiet480
|
/tests/components/ios/ @robbiet480
|
||||||
/homeassistant/components/iotawatt/ @gtdiehl @jyavenard
|
/homeassistant/components/iotawatt/ @gtdiehl @jyavenard
|
||||||
/tests/components/iotawatt/ @gtdiehl @jyavenard
|
/tests/components/iotawatt/ @gtdiehl @jyavenard
|
||||||
/homeassistant/components/iotty/ @pburgio
|
/homeassistant/components/iotty/ @pburgio @shapournemati-iotty
|
||||||
/tests/components/iotty/ @pburgio
|
/tests/components/iotty/ @pburgio @shapournemati-iotty
|
||||||
/homeassistant/components/iperf3/ @rohankapoorcom
|
/homeassistant/components/iperf3/ @rohankapoorcom
|
||||||
/homeassistant/components/ipma/ @dgomes
|
/homeassistant/components/ipma/ @dgomes
|
||||||
/tests/components/ipma/ @dgomes
|
/tests/components/ipma/ @dgomes
|
||||||
|
@ -707,8 +737,12 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/iqvia/ @bachya
|
/homeassistant/components/iqvia/ @bachya
|
||||||
/tests/components/iqvia/ @bachya
|
/tests/components/iqvia/ @bachya
|
||||||
/homeassistant/components/irish_rail_transport/ @ttroy50
|
/homeassistant/components/irish_rail_transport/ @ttroy50
|
||||||
|
/homeassistant/components/iron_os/ @tr4nt0r
|
||||||
|
/tests/components/iron_os/ @tr4nt0r
|
||||||
/homeassistant/components/isal/ @bdraco
|
/homeassistant/components/isal/ @bdraco
|
||||||
/tests/components/isal/ @bdraco
|
/tests/components/isal/ @bdraco
|
||||||
|
/homeassistant/components/iskra/ @iskramis
|
||||||
|
/tests/components/iskra/ @iskramis
|
||||||
/homeassistant/components/islamic_prayer_times/ @engrbm87 @cpfair
|
/homeassistant/components/islamic_prayer_times/ @engrbm87 @cpfair
|
||||||
/tests/components/islamic_prayer_times/ @engrbm87 @cpfair
|
/tests/components/islamic_prayer_times/ @engrbm87 @cpfair
|
||||||
/homeassistant/components/israel_rail/ @shaiu
|
/homeassistant/components/israel_rail/ @shaiu
|
||||||
|
@ -785,8 +819,12 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/leaone/ @bdraco
|
/tests/components/leaone/ @bdraco
|
||||||
/homeassistant/components/led_ble/ @bdraco
|
/homeassistant/components/led_ble/ @bdraco
|
||||||
/tests/components/led_ble/ @bdraco
|
/tests/components/led_ble/ @bdraco
|
||||||
|
/homeassistant/components/lektrico/ @lektrico
|
||||||
|
/tests/components/lektrico/ @lektrico
|
||||||
/homeassistant/components/lg_netcast/ @Drafteed @splinter98
|
/homeassistant/components/lg_netcast/ @Drafteed @splinter98
|
||||||
/tests/components/lg_netcast/ @Drafteed @splinter98
|
/tests/components/lg_netcast/ @Drafteed @splinter98
|
||||||
|
/homeassistant/components/lg_thinq/ @LG-ThinQ-Integration
|
||||||
|
/tests/components/lg_thinq/ @LG-ThinQ-Integration
|
||||||
/homeassistant/components/lidarr/ @tkdrob
|
/homeassistant/components/lidarr/ @tkdrob
|
||||||
/tests/components/lidarr/ @tkdrob
|
/tests/components/lidarr/ @tkdrob
|
||||||
/homeassistant/components/lifx/ @Djelibeybi
|
/homeassistant/components/lifx/ @Djelibeybi
|
||||||
|
@ -816,8 +854,6 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/logbook/ @home-assistant/core
|
/tests/components/logbook/ @home-assistant/core
|
||||||
/homeassistant/components/logger/ @home-assistant/core
|
/homeassistant/components/logger/ @home-assistant/core
|
||||||
/tests/components/logger/ @home-assistant/core
|
/tests/components/logger/ @home-assistant/core
|
||||||
/homeassistant/components/logi_circle/ @evanjd
|
|
||||||
/tests/components/logi_circle/ @evanjd
|
|
||||||
/homeassistant/components/london_underground/ @jpbede
|
/homeassistant/components/london_underground/ @jpbede
|
||||||
/tests/components/london_underground/ @jpbede
|
/tests/components/london_underground/ @jpbede
|
||||||
/homeassistant/components/lookin/ @ANMalko @bdraco
|
/homeassistant/components/lookin/ @ANMalko @bdraco
|
||||||
|
@ -833,13 +869,14 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/lupusec/ @majuss @suaveolent
|
/tests/components/lupusec/ @majuss @suaveolent
|
||||||
/homeassistant/components/lutron/ @cdheiser @wilburCForce
|
/homeassistant/components/lutron/ @cdheiser @wilburCForce
|
||||||
/tests/components/lutron/ @cdheiser @wilburCForce
|
/tests/components/lutron/ @cdheiser @wilburCForce
|
||||||
/homeassistant/components/lutron_caseta/ @swails @bdraco @danaues @eclair4151
|
/homeassistant/components/lutron_caseta/ @swails @danaues @eclair4151
|
||||||
/tests/components/lutron_caseta/ @swails @bdraco @danaues @eclair4151
|
/tests/components/lutron_caseta/ @swails @danaues @eclair4151
|
||||||
/homeassistant/components/lyric/ @timmo001
|
/homeassistant/components/lyric/ @timmo001
|
||||||
/tests/components/lyric/ @timmo001
|
/tests/components/lyric/ @timmo001
|
||||||
/homeassistant/components/madvr/ @iloveicedgreentea
|
/homeassistant/components/madvr/ @iloveicedgreentea
|
||||||
/tests/components/madvr/ @iloveicedgreentea
|
/tests/components/madvr/ @iloveicedgreentea
|
||||||
/homeassistant/components/mastodon/ @fabaff
|
/homeassistant/components/mastodon/ @fabaff @andrew-codechimp
|
||||||
|
/tests/components/mastodon/ @fabaff @andrew-codechimp
|
||||||
/homeassistant/components/matrix/ @PaarthShah
|
/homeassistant/components/matrix/ @PaarthShah
|
||||||
/tests/components/matrix/ @PaarthShah
|
/tests/components/matrix/ @PaarthShah
|
||||||
/homeassistant/components/matter/ @home-assistant/matter
|
/homeassistant/components/matter/ @home-assistant/matter
|
||||||
|
@ -896,6 +933,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/modern_forms/ @wonderslug
|
/tests/components/modern_forms/ @wonderslug
|
||||||
/homeassistant/components/moehlenhoff_alpha2/ @j-a-n
|
/homeassistant/components/moehlenhoff_alpha2/ @j-a-n
|
||||||
/tests/components/moehlenhoff_alpha2/ @j-a-n
|
/tests/components/moehlenhoff_alpha2/ @j-a-n
|
||||||
|
/homeassistant/components/monarch_money/ @jeeftor
|
||||||
|
/tests/components/monarch_money/ @jeeftor
|
||||||
/homeassistant/components/monoprice/ @etsinko @OnFreund
|
/homeassistant/components/monoprice/ @etsinko @OnFreund
|
||||||
/tests/components/monoprice/ @etsinko @OnFreund
|
/tests/components/monoprice/ @etsinko @OnFreund
|
||||||
/homeassistant/components/monzo/ @jakemartin-icl
|
/homeassistant/components/monzo/ @jakemartin-icl
|
||||||
|
@ -917,6 +956,8 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/msteams/ @peroyvind
|
/homeassistant/components/msteams/ @peroyvind
|
||||||
/homeassistant/components/mullvad/ @meichthys
|
/homeassistant/components/mullvad/ @meichthys
|
||||||
/tests/components/mullvad/ @meichthys
|
/tests/components/mullvad/ @meichthys
|
||||||
|
/homeassistant/components/music_assistant/ @music-assistant
|
||||||
|
/tests/components/music_assistant/ @music-assistant
|
||||||
/homeassistant/components/mutesync/ @currentoor
|
/homeassistant/components/mutesync/ @currentoor
|
||||||
/tests/components/mutesync/ @currentoor
|
/tests/components/mutesync/ @currentoor
|
||||||
/homeassistant/components/my/ @home-assistant/core
|
/homeassistant/components/my/ @home-assistant/core
|
||||||
|
@ -931,6 +972,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/nam/ @bieniu
|
/tests/components/nam/ @bieniu
|
||||||
/homeassistant/components/nanoleaf/ @milanmeu @joostlek
|
/homeassistant/components/nanoleaf/ @milanmeu @joostlek
|
||||||
/tests/components/nanoleaf/ @milanmeu @joostlek
|
/tests/components/nanoleaf/ @milanmeu @joostlek
|
||||||
|
/homeassistant/components/nasweb/ @nasWebio
|
||||||
|
/tests/components/nasweb/ @nasWebio
|
||||||
/homeassistant/components/neato/ @Santobert
|
/homeassistant/components/neato/ @Santobert
|
||||||
/tests/components/neato/ @Santobert
|
/tests/components/neato/ @Santobert
|
||||||
/homeassistant/components/nederlandse_spoorwegen/ @YarmoM
|
/homeassistant/components/nederlandse_spoorwegen/ @YarmoM
|
||||||
|
@ -959,6 +1002,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/nfandroidtv/ @tkdrob
|
/tests/components/nfandroidtv/ @tkdrob
|
||||||
/homeassistant/components/nibe_heatpump/ @elupus
|
/homeassistant/components/nibe_heatpump/ @elupus
|
||||||
/tests/components/nibe_heatpump/ @elupus
|
/tests/components/nibe_heatpump/ @elupus
|
||||||
|
/homeassistant/components/nice_go/ @IceBotYT
|
||||||
|
/tests/components/nice_go/ @IceBotYT
|
||||||
/homeassistant/components/nightscout/ @marciogranzotto
|
/homeassistant/components/nightscout/ @marciogranzotto
|
||||||
/tests/components/nightscout/ @marciogranzotto
|
/tests/components/nightscout/ @marciogranzotto
|
||||||
/homeassistant/components/nilu/ @hfurubotten
|
/homeassistant/components/nilu/ @hfurubotten
|
||||||
|
@ -969,6 +1014,8 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/noaa_tides/ @jdelaney72
|
/homeassistant/components/noaa_tides/ @jdelaney72
|
||||||
/homeassistant/components/nobo_hub/ @echoromeo @oyvindwe
|
/homeassistant/components/nobo_hub/ @echoromeo @oyvindwe
|
||||||
/tests/components/nobo_hub/ @echoromeo @oyvindwe
|
/tests/components/nobo_hub/ @echoromeo @oyvindwe
|
||||||
|
/homeassistant/components/nordpool/ @gjohansson-ST
|
||||||
|
/tests/components/nordpool/ @gjohansson-ST
|
||||||
/homeassistant/components/notify/ @home-assistant/core
|
/homeassistant/components/notify/ @home-assistant/core
|
||||||
/tests/components/notify/ @home-assistant/core
|
/tests/components/notify/ @home-assistant/core
|
||||||
/homeassistant/components/notify_events/ @matrozov @papajojo
|
/homeassistant/components/notify_events/ @matrozov @papajojo
|
||||||
|
@ -991,6 +1038,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/nut/ @bdraco @ollo69 @pestevez
|
/tests/components/nut/ @bdraco @ollo69 @pestevez
|
||||||
/homeassistant/components/nws/ @MatthewFlamm @kamiyo
|
/homeassistant/components/nws/ @MatthewFlamm @kamiyo
|
||||||
/tests/components/nws/ @MatthewFlamm @kamiyo
|
/tests/components/nws/ @MatthewFlamm @kamiyo
|
||||||
|
/homeassistant/components/nyt_games/ @joostlek
|
||||||
|
/tests/components/nyt_games/ @joostlek
|
||||||
/homeassistant/components/nzbget/ @chriscla
|
/homeassistant/components/nzbget/ @chriscla
|
||||||
/tests/components/nzbget/ @chriscla
|
/tests/components/nzbget/ @chriscla
|
||||||
/homeassistant/components/obihai/ @dshokouhi @ejpenney
|
/homeassistant/components/obihai/ @dshokouhi @ejpenney
|
||||||
|
@ -1010,6 +1059,7 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/onewire/ @garbled1 @epenet
|
/homeassistant/components/onewire/ @garbled1 @epenet
|
||||||
/tests/components/onewire/ @garbled1 @epenet
|
/tests/components/onewire/ @garbled1 @epenet
|
||||||
/homeassistant/components/onkyo/ @arturpragacz
|
/homeassistant/components/onkyo/ @arturpragacz
|
||||||
|
/tests/components/onkyo/ @arturpragacz
|
||||||
/homeassistant/components/onvif/ @hunterjm
|
/homeassistant/components/onvif/ @hunterjm
|
||||||
/tests/components/onvif/ @hunterjm
|
/tests/components/onvif/ @hunterjm
|
||||||
/homeassistant/components/open_meteo/ @frenck
|
/homeassistant/components/open_meteo/ @frenck
|
||||||
|
@ -1045,16 +1095,16 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/otbr/ @home-assistant/core
|
/tests/components/otbr/ @home-assistant/core
|
||||||
/homeassistant/components/ourgroceries/ @OnFreund
|
/homeassistant/components/ourgroceries/ @OnFreund
|
||||||
/tests/components/ourgroceries/ @OnFreund
|
/tests/components/ourgroceries/ @OnFreund
|
||||||
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev @tronix117
|
/homeassistant/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev @tronix117 @alexfp14
|
||||||
/tests/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev @tronix117
|
/tests/components/overkiz/ @imicknl @vlebourl @tetienne @nyroDev @tronix117 @alexfp14
|
||||||
/homeassistant/components/ovo_energy/ @timmo001
|
/homeassistant/components/ovo_energy/ @timmo001
|
||||||
/tests/components/ovo_energy/ @timmo001
|
/tests/components/ovo_energy/ @timmo001
|
||||||
/homeassistant/components/p1_monitor/ @klaasnicolaas
|
/homeassistant/components/p1_monitor/ @klaasnicolaas
|
||||||
/tests/components/p1_monitor/ @klaasnicolaas
|
/tests/components/p1_monitor/ @klaasnicolaas
|
||||||
|
/homeassistant/components/palazzetti/ @dotvav
|
||||||
|
/tests/components/palazzetti/ @dotvav
|
||||||
/homeassistant/components/panel_custom/ @home-assistant/frontend
|
/homeassistant/components/panel_custom/ @home-assistant/frontend
|
||||||
/tests/components/panel_custom/ @home-assistant/frontend
|
/tests/components/panel_custom/ @home-assistant/frontend
|
||||||
/homeassistant/components/panel_iframe/ @home-assistant/frontend
|
|
||||||
/tests/components/panel_iframe/ @home-assistant/frontend
|
|
||||||
/homeassistant/components/peco/ @IceBotYT
|
/homeassistant/components/peco/ @IceBotYT
|
||||||
/tests/components/peco/ @IceBotYT
|
/tests/components/peco/ @IceBotYT
|
||||||
/homeassistant/components/pegel_online/ @mib1185
|
/homeassistant/components/pegel_online/ @mib1185
|
||||||
|
@ -1069,8 +1119,6 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/pi_hole/ @shenxn
|
/tests/components/pi_hole/ @shenxn
|
||||||
/homeassistant/components/picnic/ @corneyl
|
/homeassistant/components/picnic/ @corneyl
|
||||||
/tests/components/picnic/ @corneyl
|
/tests/components/picnic/ @corneyl
|
||||||
/homeassistant/components/pilight/ @trekky12
|
|
||||||
/tests/components/pilight/ @trekky12
|
|
||||||
/homeassistant/components/ping/ @jpbede
|
/homeassistant/components/ping/ @jpbede
|
||||||
/tests/components/ping/ @jpbede
|
/tests/components/ping/ @jpbede
|
||||||
/homeassistant/components/plaato/ @JohNan
|
/homeassistant/components/plaato/ @JohNan
|
||||||
|
@ -1100,8 +1148,8 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/proximity/ @mib1185
|
/homeassistant/components/proximity/ @mib1185
|
||||||
/tests/components/proximity/ @mib1185
|
/tests/components/proximity/ @mib1185
|
||||||
/homeassistant/components/proxmoxve/ @jhollowe @Corbeno
|
/homeassistant/components/proxmoxve/ @jhollowe @Corbeno
|
||||||
/homeassistant/components/prusalink/ @balloob @Skaronator
|
/homeassistant/components/prusalink/ @balloob
|
||||||
/tests/components/prusalink/ @balloob @Skaronator
|
/tests/components/prusalink/ @balloob
|
||||||
/homeassistant/components/ps4/ @ktnrg45
|
/homeassistant/components/ps4/ @ktnrg45
|
||||||
/tests/components/ps4/ @ktnrg45
|
/tests/components/ps4/ @ktnrg45
|
||||||
/homeassistant/components/pure_energie/ @klaasnicolaas
|
/homeassistant/components/pure_energie/ @klaasnicolaas
|
||||||
|
@ -1204,8 +1252,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/roku/ @ctalkington
|
/tests/components/roku/ @ctalkington
|
||||||
/homeassistant/components/romy/ @xeniter
|
/homeassistant/components/romy/ @xeniter
|
||||||
/tests/components/romy/ @xeniter
|
/tests/components/romy/ @xeniter
|
||||||
/homeassistant/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1 @Orhideous
|
/homeassistant/components/roomba/ @pschmitt @cyr-ius @shenxn @Orhideous
|
||||||
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1 @Orhideous
|
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn @Orhideous
|
||||||
/homeassistant/components/roon/ @pavoni
|
/homeassistant/components/roon/ @pavoni
|
||||||
/tests/components/roon/ @pavoni
|
/tests/components/roon/ @pavoni
|
||||||
/homeassistant/components/rpi_power/ @shenxn @swetoast
|
/homeassistant/components/rpi_power/ @shenxn @swetoast
|
||||||
|
@ -1262,6 +1310,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/sensorpro/ @bdraco
|
/tests/components/sensorpro/ @bdraco
|
||||||
/homeassistant/components/sensorpush/ @bdraco
|
/homeassistant/components/sensorpush/ @bdraco
|
||||||
/tests/components/sensorpush/ @bdraco
|
/tests/components/sensorpush/ @bdraco
|
||||||
|
/homeassistant/components/sensoterra/ @markruys
|
||||||
|
/tests/components/sensoterra/ @markruys
|
||||||
/homeassistant/components/sentry/ @dcramer @frenck
|
/homeassistant/components/sentry/ @dcramer @frenck
|
||||||
/tests/components/sentry/ @dcramer @frenck
|
/tests/components/sentry/ @dcramer @frenck
|
||||||
/homeassistant/components/senz/ @milanmeu
|
/homeassistant/components/senz/ @milanmeu
|
||||||
|
@ -1296,6 +1346,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/siren/ @home-assistant/core @raman325
|
/tests/components/siren/ @home-assistant/core @raman325
|
||||||
/homeassistant/components/sisyphus/ @jkeljo
|
/homeassistant/components/sisyphus/ @jkeljo
|
||||||
/homeassistant/components/sky_hub/ @rogerselwyn
|
/homeassistant/components/sky_hub/ @rogerselwyn
|
||||||
|
/homeassistant/components/sky_remote/ @dunnmj @saty9
|
||||||
|
/tests/components/sky_remote/ @dunnmj @saty9
|
||||||
/homeassistant/components/skybell/ @tkdrob
|
/homeassistant/components/skybell/ @tkdrob
|
||||||
/tests/components/skybell/ @tkdrob
|
/tests/components/skybell/ @tkdrob
|
||||||
/homeassistant/components/slack/ @tkdrob @fletcherau
|
/homeassistant/components/slack/ @tkdrob @fletcherau
|
||||||
|
@ -1314,8 +1366,11 @@ build.json @home-assistant/supervisor
|
||||||
/homeassistant/components/smarttub/ @mdz
|
/homeassistant/components/smarttub/ @mdz
|
||||||
/tests/components/smarttub/ @mdz
|
/tests/components/smarttub/ @mdz
|
||||||
/homeassistant/components/smarty/ @z0mbieprocess
|
/homeassistant/components/smarty/ @z0mbieprocess
|
||||||
|
/tests/components/smarty/ @z0mbieprocess
|
||||||
/homeassistant/components/smhi/ @gjohansson-ST
|
/homeassistant/components/smhi/ @gjohansson-ST
|
||||||
/tests/components/smhi/ @gjohansson-ST
|
/tests/components/smhi/ @gjohansson-ST
|
||||||
|
/homeassistant/components/smlight/ @tl-sl
|
||||||
|
/tests/components/smlight/ @tl-sl
|
||||||
/homeassistant/components/sms/ @ocalvo
|
/homeassistant/components/sms/ @ocalvo
|
||||||
/tests/components/sms/ @ocalvo
|
/tests/components/sms/ @ocalvo
|
||||||
/homeassistant/components/snapcast/ @luar123
|
/homeassistant/components/snapcast/ @luar123
|
||||||
|
@ -1345,15 +1400,13 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/spaceapi/ @fabaff
|
/tests/components/spaceapi/ @fabaff
|
||||||
/homeassistant/components/speedtestdotnet/ @rohankapoorcom @engrbm87
|
/homeassistant/components/speedtestdotnet/ @rohankapoorcom @engrbm87
|
||||||
/tests/components/speedtestdotnet/ @rohankapoorcom @engrbm87
|
/tests/components/speedtestdotnet/ @rohankapoorcom @engrbm87
|
||||||
/homeassistant/components/spider/ @peternijssen
|
|
||||||
/tests/components/spider/ @peternijssen
|
|
||||||
/homeassistant/components/splunk/ @Bre77
|
/homeassistant/components/splunk/ @Bre77
|
||||||
/homeassistant/components/spotify/ @frenck @joostlek
|
/homeassistant/components/spotify/ @frenck @joostlek
|
||||||
/tests/components/spotify/ @frenck @joostlek
|
/tests/components/spotify/ @frenck @joostlek
|
||||||
/homeassistant/components/sql/ @gjohansson-ST @dougiteixeira
|
/homeassistant/components/sql/ @gjohansson-ST @dougiteixeira
|
||||||
/tests/components/sql/ @gjohansson-ST @dougiteixeira
|
/tests/components/sql/ @gjohansson-ST @dougiteixeira
|
||||||
/homeassistant/components/squeezebox/ @rajlaud
|
/homeassistant/components/squeezebox/ @rajlaud @pssc @peteS-UK
|
||||||
/tests/components/squeezebox/ @rajlaud
|
/tests/components/squeezebox/ @rajlaud @pssc @peteS-UK
|
||||||
/homeassistant/components/srp_energy/ @briglx
|
/homeassistant/components/srp_energy/ @briglx
|
||||||
/tests/components/srp_energy/ @briglx
|
/tests/components/srp_energy/ @briglx
|
||||||
/homeassistant/components/starline/ @anonym-tsk
|
/homeassistant/components/starline/ @anonym-tsk
|
||||||
|
@ -1377,8 +1430,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/stt/ @home-assistant/core
|
/tests/components/stt/ @home-assistant/core
|
||||||
/homeassistant/components/subaru/ @G-Two
|
/homeassistant/components/subaru/ @G-Two
|
||||||
/tests/components/subaru/ @G-Two
|
/tests/components/subaru/ @G-Two
|
||||||
/homeassistant/components/suez_water/ @ooii
|
/homeassistant/components/suez_water/ @ooii @jb101010-2
|
||||||
/tests/components/suez_water/ @ooii
|
/tests/components/suez_water/ @ooii @jb101010-2
|
||||||
/homeassistant/components/sun/ @Swamp-Ig
|
/homeassistant/components/sun/ @Swamp-Ig
|
||||||
/tests/components/sun/ @Swamp-Ig
|
/tests/components/sun/ @Swamp-Ig
|
||||||
/homeassistant/components/sunweg/ @rokam
|
/homeassistant/components/sunweg/ @rokam
|
||||||
|
@ -1397,10 +1450,10 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/switchbee/ @jafar-atili
|
/tests/components/switchbee/ @jafar-atili
|
||||||
/homeassistant/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski
|
/homeassistant/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski
|
||||||
/tests/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski
|
/tests/components/switchbot/ @danielhiversen @RenierM26 @murtas @Eloston @dsypniewski
|
||||||
/homeassistant/components/switchbot_cloud/ @SeraphicRav @laurence-presland
|
/homeassistant/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur
|
||||||
/tests/components/switchbot_cloud/ @SeraphicRav @laurence-presland
|
/tests/components/switchbot_cloud/ @SeraphicRav @laurence-presland @Gigatrappeur
|
||||||
/homeassistant/components/switcher_kis/ @thecode
|
/homeassistant/components/switcher_kis/ @thecode @YogevBokobza
|
||||||
/tests/components/switcher_kis/ @thecode
|
/tests/components/switcher_kis/ @thecode @YogevBokobza
|
||||||
/homeassistant/components/switchmate/ @danielhiversen @qiz-li
|
/homeassistant/components/switchmate/ @danielhiversen @qiz-li
|
||||||
/homeassistant/components/syncthing/ @zhulik
|
/homeassistant/components/syncthing/ @zhulik
|
||||||
/tests/components/syncthing/ @zhulik
|
/tests/components/syncthing/ @zhulik
|
||||||
|
@ -1436,8 +1489,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/tedee/ @patrickhilker @zweckj
|
/tests/components/tedee/ @patrickhilker @zweckj
|
||||||
/homeassistant/components/tellduslive/ @fredrike
|
/homeassistant/components/tellduslive/ @fredrike
|
||||||
/tests/components/tellduslive/ @fredrike
|
/tests/components/tellduslive/ @fredrike
|
||||||
/homeassistant/components/template/ @PhracturedBlue @tetienne @home-assistant/core
|
/homeassistant/components/template/ @PhracturedBlue @home-assistant/core
|
||||||
/tests/components/template/ @PhracturedBlue @tetienne @home-assistant/core
|
/tests/components/template/ @PhracturedBlue @home-assistant/core
|
||||||
/homeassistant/components/tesla_fleet/ @Bre77
|
/homeassistant/components/tesla_fleet/ @Bre77
|
||||||
/tests/components/tesla_fleet/ @Bre77
|
/tests/components/tesla_fleet/ @Bre77
|
||||||
/homeassistant/components/tesla_wall_connector/ @einarhauks
|
/homeassistant/components/tesla_wall_connector/ @einarhauks
|
||||||
|
@ -1478,6 +1531,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/tomorrowio/ @raman325 @lymanepp
|
/tests/components/tomorrowio/ @raman325 @lymanepp
|
||||||
/homeassistant/components/totalconnect/ @austinmroczek
|
/homeassistant/components/totalconnect/ @austinmroczek
|
||||||
/tests/components/totalconnect/ @austinmroczek
|
/tests/components/totalconnect/ @austinmroczek
|
||||||
|
/homeassistant/components/touchline_sl/ @jnsgruk
|
||||||
|
/tests/components/touchline_sl/ @jnsgruk
|
||||||
/homeassistant/components/tplink/ @rytilahti @bdraco @sdb9696
|
/homeassistant/components/tplink/ @rytilahti @bdraco @sdb9696
|
||||||
/tests/components/tplink/ @rytilahti @bdraco @sdb9696
|
/tests/components/tplink/ @rytilahti @bdraco @sdb9696
|
||||||
/homeassistant/components/tplink_omada/ @MarkGodwin
|
/homeassistant/components/tplink_omada/ @MarkGodwin
|
||||||
|
@ -1502,6 +1557,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/transmission/ @engrbm87 @JPHutchins
|
/tests/components/transmission/ @engrbm87 @JPHutchins
|
||||||
/homeassistant/components/trend/ @jpbede
|
/homeassistant/components/trend/ @jpbede
|
||||||
/tests/components/trend/ @jpbede
|
/tests/components/trend/ @jpbede
|
||||||
|
/homeassistant/components/triggercmd/ @rvmey
|
||||||
|
/tests/components/triggercmd/ @rvmey
|
||||||
/homeassistant/components/tts/ @home-assistant/core
|
/homeassistant/components/tts/ @home-assistant/core
|
||||||
/tests/components/tts/ @home-assistant/core
|
/tests/components/tts/ @home-assistant/core
|
||||||
/homeassistant/components/tuya/ @Tuya @zlinoliver @frenck
|
/homeassistant/components/tuya/ @Tuya @zlinoliver @frenck
|
||||||
|
@ -1606,6 +1663,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/webostv/ @thecode
|
/tests/components/webostv/ @thecode
|
||||||
/homeassistant/components/websocket_api/ @home-assistant/core
|
/homeassistant/components/websocket_api/ @home-assistant/core
|
||||||
/tests/components/websocket_api/ @home-assistant/core
|
/tests/components/websocket_api/ @home-assistant/core
|
||||||
|
/homeassistant/components/weheat/ @jesperraemaekers
|
||||||
|
/tests/components/weheat/ @jesperraemaekers
|
||||||
/homeassistant/components/wemo/ @esev
|
/homeassistant/components/wemo/ @esev
|
||||||
/tests/components/wemo/ @esev
|
/tests/components/wemo/ @esev
|
||||||
/homeassistant/components/whirlpool/ @abmantis @mkmer
|
/homeassistant/components/whirlpool/ @abmantis @mkmer
|
||||||
|
@ -1623,6 +1682,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/wiz/ @sbidy
|
/tests/components/wiz/ @sbidy
|
||||||
/homeassistant/components/wled/ @frenck
|
/homeassistant/components/wled/ @frenck
|
||||||
/tests/components/wled/ @frenck
|
/tests/components/wled/ @frenck
|
||||||
|
/homeassistant/components/wmspro/ @mback2k
|
||||||
|
/tests/components/wmspro/ @mback2k
|
||||||
/homeassistant/components/wolflink/ @adamkrol93 @mtielen
|
/homeassistant/components/wolflink/ @adamkrol93 @mtielen
|
||||||
/tests/components/wolflink/ @adamkrol93 @mtielen
|
/tests/components/wolflink/ @adamkrol93 @mtielen
|
||||||
/homeassistant/components/workday/ @fabaff @gjohansson-ST
|
/homeassistant/components/workday/ @fabaff @gjohansson-ST
|
||||||
|
@ -1643,6 +1704,8 @@ build.json @home-assistant/supervisor
|
||||||
/tests/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG
|
/tests/components/xiaomi_miio/ @rytilahti @syssi @starkillerOG
|
||||||
/homeassistant/components/xiaomi_tv/ @simse
|
/homeassistant/components/xiaomi_tv/ @simse
|
||||||
/homeassistant/components/xmpp/ @fabaff @flowolf
|
/homeassistant/components/xmpp/ @fabaff @flowolf
|
||||||
|
/homeassistant/components/yale/ @bdraco
|
||||||
|
/tests/components/yale/ @bdraco
|
||||||
/homeassistant/components/yale_smart_alarm/ @gjohansson-ST
|
/homeassistant/components/yale_smart_alarm/ @gjohansson-ST
|
||||||
/tests/components/yale_smart_alarm/ @gjohansson-ST
|
/tests/components/yale_smart_alarm/ @gjohansson-ST
|
||||||
/homeassistant/components/yalexs_ble/ @bdraco
|
/homeassistant/components/yalexs_ble/ @bdraco
|
||||||
|
|
32
Dockerfile
32
Dockerfile
|
@ -7,12 +7,13 @@ FROM ${BUILD_FROM}
|
||||||
# Synchronize with homeassistant/core.py:async_stop
|
# Synchronize with homeassistant/core.py:async_stop
|
||||||
ENV \
|
ENV \
|
||||||
S6_SERVICES_GRACETIME=240000 \
|
S6_SERVICES_GRACETIME=240000 \
|
||||||
UV_SYSTEM_PYTHON=true
|
UV_SYSTEM_PYTHON=true \
|
||||||
|
UV_NO_CACHE=true
|
||||||
|
|
||||||
ARG QEMU_CPU
|
ARG QEMU_CPU
|
||||||
|
|
||||||
# Install uv
|
# Install uv
|
||||||
RUN pip3 install uv==0.2.27
|
RUN pip3 install uv==0.5.0
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
|
@ -29,15 +30,9 @@ RUN \
|
||||||
if ls homeassistant/home_assistant_*.whl 1> /dev/null 2>&1; then \
|
if ls homeassistant/home_assistant_*.whl 1> /dev/null 2>&1; then \
|
||||||
uv pip install homeassistant/home_assistant_*.whl; \
|
uv pip install homeassistant/home_assistant_*.whl; \
|
||||||
fi \
|
fi \
|
||||||
&& if [ "${BUILD_ARCH}" = "i386" ]; then \
|
&& uv pip install \
|
||||||
linux32 uv pip install \
|
--no-build \
|
||||||
--no-build \
|
-r homeassistant/requirements_all.txt
|
||||||
-r homeassistant/requirements_all.txt; \
|
|
||||||
else \
|
|
||||||
uv pip install \
|
|
||||||
--no-build \
|
|
||||||
-r homeassistant/requirements_all.txt; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Setup Home Assistant Core
|
## Setup Home Assistant Core
|
||||||
COPY . homeassistant/
|
COPY . homeassistant/
|
||||||
|
@ -50,4 +45,19 @@ RUN \
|
||||||
# Home Assistant S6-Overlay
|
# Home Assistant S6-Overlay
|
||||||
COPY rootfs /
|
COPY rootfs /
|
||||||
|
|
||||||
|
# Needs to be redefined inside the FROM statement to be set for RUN commands
|
||||||
|
ARG BUILD_ARCH
|
||||||
|
# Get go2rtc binary
|
||||||
|
RUN \
|
||||||
|
case "${BUILD_ARCH}" in \
|
||||||
|
"aarch64") go2rtc_suffix='arm64' ;; \
|
||||||
|
"armhf") go2rtc_suffix='armv6' ;; \
|
||||||
|
"armv7") go2rtc_suffix='arm' ;; \
|
||||||
|
*) go2rtc_suffix=${BUILD_ARCH} ;; \
|
||||||
|
esac \
|
||||||
|
&& curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.7/go2rtc_linux_${go2rtc_suffix} --output /bin/go2rtc \
|
||||||
|
&& chmod +x /bin/go2rtc \
|
||||||
|
# Verify go2rtc can be executed
|
||||||
|
&& go2rtc --version
|
||||||
|
|
||||||
WORKDIR /config
|
WORKDIR /config
|
||||||
|
|
|
@ -35,6 +35,9 @@ RUN \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Add go2rtc binary
|
||||||
|
COPY --from=ghcr.io/alexxit/go2rtc:latest /usr/local/bin/go2rtc /bin/go2rtc
|
||||||
|
|
||||||
# Install uv
|
# Install uv
|
||||||
RUN pip3 install uv
|
RUN pip3 install uv
|
||||||
|
|
||||||
|
@ -42,7 +45,8 @@ WORKDIR /usr/src
|
||||||
|
|
||||||
# Setup hass-release
|
# Setup hass-release
|
||||||
RUN git clone --depth 1 https://github.com/home-assistant/hass-release \
|
RUN git clone --depth 1 https://github.com/home-assistant/hass-release \
|
||||||
&& uv pip install --system -e hass-release/
|
&& uv pip install --system -e hass-release/ \
|
||||||
|
&& chown -R vscode /usr/src/hass-release/data
|
||||||
|
|
||||||
USER vscode
|
USER vscode
|
||||||
ENV VIRTUAL_ENV="/home/vscode/.local/ha-venv"
|
ENV VIRTUAL_ENV="/home/vscode/.local/ha-venv"
|
||||||
|
|
|
@ -7,8 +7,6 @@ Check out `home-assistant.io <https://home-assistant.io>`__ for `a
|
||||||
demo <https://demo.home-assistant.io>`__, `installation instructions <https://home-assistant.io/getting-started/>`__,
|
demo <https://demo.home-assistant.io>`__, `installation instructions <https://home-assistant.io/getting-started/>`__,
|
||||||
`tutorials <https://home-assistant.io/getting-started/automation/>`__ and `documentation <https://home-assistant.io/docs/>`__.
|
`tutorials <https://home-assistant.io/getting-started/automation/>`__ and `documentation <https://home-assistant.io/docs/>`__.
|
||||||
|
|
||||||
This is a project of the `Open Home Foundation <https://www.openhomefoundation.org/>`__.
|
|
||||||
|
|
||||||
|screenshot-states|
|
|screenshot-states|
|
||||||
|
|
||||||
Featured integrations
|
Featured integrations
|
||||||
|
@ -22,9 +20,14 @@ components <https://developers.home-assistant.io/docs/creating_component_index/>
|
||||||
If you run into issues while using Home Assistant or during development
|
If you run into issues while using Home Assistant or during development
|
||||||
of a component, check the `Home Assistant help section <https://home-assistant.io/help/>`__ of our website for further help and information.
|
of a component, check the `Home Assistant help section <https://home-assistant.io/help/>`__ of our website for further help and information.
|
||||||
|
|
||||||
|
|ohf-logo|
|
||||||
|
|
||||||
.. |Chat Status| image:: https://img.shields.io/discord/330944238910963714.svg
|
.. |Chat Status| image:: https://img.shields.io/discord/330944238910963714.svg
|
||||||
:target: https://www.home-assistant.io/join-chat/
|
:target: https://www.home-assistant.io/join-chat/
|
||||||
.. |screenshot-states| image:: https://raw.githubusercontent.com/home-assistant/core/dev/.github/assets/screenshot-states.png
|
.. |screenshot-states| image:: https://raw.githubusercontent.com/home-assistant/core/dev/.github/assets/screenshot-states.png
|
||||||
:target: https://demo.home-assistant.io
|
:target: https://demo.home-assistant.io
|
||||||
.. |screenshot-integrations| image:: https://raw.githubusercontent.com/home-assistant/core/dev/.github/assets/screenshot-integrations.png
|
.. |screenshot-integrations| image:: https://raw.githubusercontent.com/home-assistant/core/dev/.github/assets/screenshot-integrations.png
|
||||||
:target: https://home-assistant.io/integrations/
|
:target: https://home-assistant.io/integrations/
|
||||||
|
.. |ohf-logo| image:: https://www.openhomefoundation.org/badges/home-assistant.png
|
||||||
|
:alt: Home Assistant - A project from the Open Home Foundation
|
||||||
|
:target: https://www.openhomefoundation.org/
|
||||||
|
|
10
build.yaml
10
build.yaml
|
@ -1,10 +1,10 @@
|
||||||
image: ghcr.io/home-assistant/{arch}-homeassistant
|
image: ghcr.io/home-assistant/{arch}-homeassistant
|
||||||
build_from:
|
build_from:
|
||||||
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2024.06.1
|
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2024.11.0
|
||||||
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2024.06.1
|
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2024.11.0
|
||||||
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2024.06.1
|
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2024.11.0
|
||||||
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2024.06.1
|
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2024.11.0
|
||||||
i386: ghcr.io/home-assistant/i386-homeassistant-base:2024.06.1
|
i386: ghcr.io/home-assistant/i386-homeassistant-base:2024.11.0
|
||||||
codenotary:
|
codenotary:
|
||||||
signer: notary@home-assistant.io
|
signer: notary@home-assistant.io
|
||||||
base_image: notary@home-assistant.io
|
base_image: notary@home-assistant.io
|
||||||
|
|
|
@ -9,6 +9,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from .backup_restore import restore_backup
|
||||||
from .const import REQUIRED_PYTHON_VER, RESTART_EXIT_CODE, __version__
|
from .const import REQUIRED_PYTHON_VER, RESTART_EXIT_CODE, __version__
|
||||||
|
|
||||||
FAULT_LOG_FILENAME = "home-assistant.log.fault"
|
FAULT_LOG_FILENAME = "home-assistant.log.fault"
|
||||||
|
@ -182,6 +183,9 @@ def main() -> int:
|
||||||
return scripts.run(args.script)
|
return scripts.run(args.script)
|
||||||
|
|
||||||
config_dir = os.path.abspath(os.path.join(os.getcwd(), args.config))
|
config_dir = os.path.abspath(os.path.join(os.getcwd(), args.config))
|
||||||
|
if restore_backup(config_dir):
|
||||||
|
return RESTART_EXIT_CODE
|
||||||
|
|
||||||
ensure_config_path(config_dir)
|
ensure_config_path(config_dir)
|
||||||
|
|
||||||
# pylint: disable-next=import-outside-toplevel
|
# pylint: disable-next=import-outside-toplevel
|
||||||
|
|
|
@ -12,7 +12,6 @@ from typing import Any, cast
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
|
|
||||||
from homeassistant import data_entry_flow
|
|
||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
CALLBACK_TYPE,
|
CALLBACK_TYPE,
|
||||||
HassJob,
|
HassJob,
|
||||||
|
@ -20,13 +19,14 @@ from homeassistant.core import (
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
callback,
|
callback,
|
||||||
)
|
)
|
||||||
|
from homeassistant.data_entry_flow import FlowHandler, FlowManager, FlowResultType
|
||||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from . import auth_store, jwt_wrapper, models
|
from . import auth_store, jwt_wrapper, models
|
||||||
from .const import ACCESS_TOKEN_EXPIRATION, GROUP_ID_ADMIN, REFRESH_TOKEN_EXPIRATION
|
from .const import ACCESS_TOKEN_EXPIRATION, GROUP_ID_ADMIN, REFRESH_TOKEN_EXPIRATION
|
||||||
from .mfa_modules import MultiFactorAuthModule, auth_mfa_module_from_config
|
from .mfa_modules import MultiFactorAuthModule, auth_mfa_module_from_config
|
||||||
from .models import AuthFlowResult
|
from .models import AuthFlowContext, AuthFlowResult
|
||||||
from .providers import AuthProvider, LoginFlow, auth_provider_from_config
|
from .providers import AuthProvider, LoginFlow, auth_provider_from_config
|
||||||
from .providers.homeassistant import HassAuthProvider
|
from .providers.homeassistant import HassAuthProvider
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ async def auth_manager_from_config(
|
||||||
|
|
||||||
|
|
||||||
class AuthManagerFlowManager(
|
class AuthManagerFlowManager(
|
||||||
data_entry_flow.FlowManager[AuthFlowResult, tuple[str, str]]
|
FlowManager[AuthFlowContext, AuthFlowResult, tuple[str, str]]
|
||||||
):
|
):
|
||||||
"""Manage authentication flows."""
|
"""Manage authentication flows."""
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class AuthManagerFlowManager(
|
||||||
self,
|
self,
|
||||||
handler_key: tuple[str, str],
|
handler_key: tuple[str, str],
|
||||||
*,
|
*,
|
||||||
context: dict[str, Any] | None = None,
|
context: AuthFlowContext | None = None,
|
||||||
data: dict[str, Any] | None = None,
|
data: dict[str, Any] | None = None,
|
||||||
) -> LoginFlow:
|
) -> LoginFlow:
|
||||||
"""Create a login flow."""
|
"""Create a login flow."""
|
||||||
|
@ -124,13 +124,17 @@ class AuthManagerFlowManager(
|
||||||
|
|
||||||
async def async_finish_flow(
|
async def async_finish_flow(
|
||||||
self,
|
self,
|
||||||
flow: data_entry_flow.FlowHandler[AuthFlowResult, tuple[str, str]],
|
flow: FlowHandler[AuthFlowContext, AuthFlowResult, tuple[str, str]],
|
||||||
result: AuthFlowResult,
|
result: AuthFlowResult,
|
||||||
) -> AuthFlowResult:
|
) -> AuthFlowResult:
|
||||||
"""Return a user as result of login flow."""
|
"""Return a user as result of login flow.
|
||||||
|
|
||||||
|
This method is called when a flow step returns FlowResultType.ABORT or
|
||||||
|
FlowResultType.CREATE_ENTRY.
|
||||||
|
"""
|
||||||
flow = cast(LoginFlow, flow)
|
flow = cast(LoginFlow, flow)
|
||||||
|
|
||||||
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
|
if result["type"] != FlowResultType.CREATE_ENTRY:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# we got final result
|
# we got final result
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import cached_property
|
from ipaddress import IPv4Address, IPv6Address
|
||||||
import secrets
|
import secrets
|
||||||
from typing import Any, NamedTuple
|
from typing import Any, NamedTuple
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -11,9 +11,10 @@ import uuid
|
||||||
import attr
|
import attr
|
||||||
from attr import Attribute
|
from attr import Attribute
|
||||||
from attr.setters import validate
|
from attr.setters import validate
|
||||||
|
from propcache import cached_property
|
||||||
|
|
||||||
from homeassistant.const import __version__
|
from homeassistant.const import __version__
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowContext, FlowResult
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from . import permissions as perm_mdl
|
from . import permissions as perm_mdl
|
||||||
|
@ -23,7 +24,16 @@ TOKEN_TYPE_NORMAL = "normal"
|
||||||
TOKEN_TYPE_SYSTEM = "system"
|
TOKEN_TYPE_SYSTEM = "system"
|
||||||
TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN = "long_lived_access_token"
|
TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN = "long_lived_access_token"
|
||||||
|
|
||||||
AuthFlowResult = FlowResult[tuple[str, str]]
|
|
||||||
|
class AuthFlowContext(FlowContext, total=False):
|
||||||
|
"""Typed context dict for auth flow."""
|
||||||
|
|
||||||
|
credential_only: bool
|
||||||
|
ip_address: IPv4Address | IPv6Address
|
||||||
|
redirect_uri: str
|
||||||
|
|
||||||
|
|
||||||
|
AuthFlowResult = FlowResult[AuthFlowContext, tuple[str, str]]
|
||||||
|
|
||||||
|
|
||||||
@attr.s(slots=True)
|
@attr.s(slots=True)
|
||||||
|
|
|
@ -18,9 +18,12 @@ from homeassistant.const import (
|
||||||
EVENT_THEMES_UPDATED,
|
EVENT_THEMES_UPDATED,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.area_registry import EVENT_AREA_REGISTRY_UPDATED
|
from homeassistant.helpers.area_registry import EVENT_AREA_REGISTRY_UPDATED
|
||||||
|
from homeassistant.helpers.category_registry import EVENT_CATEGORY_REGISTRY_UPDATED
|
||||||
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
|
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
|
||||||
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
||||||
|
from homeassistant.helpers.floor_registry import EVENT_FLOOR_REGISTRY_UPDATED
|
||||||
from homeassistant.helpers.issue_registry import EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED
|
from homeassistant.helpers.issue_registry import EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED
|
||||||
|
from homeassistant.helpers.label_registry import EVENT_LABEL_REGISTRY_UPDATED
|
||||||
from homeassistant.util.event_type import EventType
|
from homeassistant.util.event_type import EventType
|
||||||
|
|
||||||
# These are events that do not contain any sensitive data
|
# These are events that do not contain any sensitive data
|
||||||
|
@ -41,4 +44,7 @@ SUBSCRIBE_ALLOWLIST: Final[set[EventType[Any] | str]] = {
|
||||||
EVENT_SHOPPING_LIST_UPDATED,
|
EVENT_SHOPPING_LIST_UPDATED,
|
||||||
EVENT_STATE_CHANGED,
|
EVENT_STATE_CHANGED,
|
||||||
EVENT_THEMES_UPDATED,
|
EVENT_THEMES_UPDATED,
|
||||||
|
EVENT_LABEL_REGISTRY_UPDATED,
|
||||||
|
EVENT_CATEGORY_REGISTRY_UPDATED,
|
||||||
|
EVENT_FLOOR_REGISTRY_UPDATED,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,10 @@ from typing import Any
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from voluptuous.humanize import humanize_error
|
from voluptuous.humanize import humanize_error
|
||||||
|
|
||||||
from homeassistant import data_entry_flow, requirements
|
from homeassistant import requirements
|
||||||
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
|
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.data_entry_flow import FlowHandler
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.importlib import async_import_module
|
from homeassistant.helpers.importlib import async_import_module
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
@ -21,7 +22,14 @@ from homeassistant.util.hass_dict import HassKey
|
||||||
|
|
||||||
from ..auth_store import AuthStore
|
from ..auth_store import AuthStore
|
||||||
from ..const import MFA_SESSION_EXPIRATION
|
from ..const import MFA_SESSION_EXPIRATION
|
||||||
from ..models import AuthFlowResult, Credentials, RefreshToken, User, UserMeta
|
from ..models import (
|
||||||
|
AuthFlowContext,
|
||||||
|
AuthFlowResult,
|
||||||
|
Credentials,
|
||||||
|
RefreshToken,
|
||||||
|
User,
|
||||||
|
UserMeta,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DATA_REQS: HassKey[set[str]] = HassKey("auth_prov_reqs_processed")
|
DATA_REQS: HassKey[set[str]] = HassKey("auth_prov_reqs_processed")
|
||||||
|
@ -97,7 +105,7 @@ class AuthProvider:
|
||||||
|
|
||||||
# Implement by extending class
|
# Implement by extending class
|
||||||
|
|
||||||
async def async_login_flow(self, context: dict[str, Any] | None) -> LoginFlow:
|
async def async_login_flow(self, context: AuthFlowContext | None) -> LoginFlow:
|
||||||
"""Return the data flow for logging in with auth provider.
|
"""Return the data flow for logging in with auth provider.
|
||||||
|
|
||||||
Auth provider should extend LoginFlow and return an instance.
|
Auth provider should extend LoginFlow and return an instance.
|
||||||
|
@ -184,7 +192,7 @@ async def load_auth_provider_module(
|
||||||
return module
|
return module
|
||||||
|
|
||||||
|
|
||||||
class LoginFlow(data_entry_flow.FlowHandler[AuthFlowResult, tuple[str, str]]):
|
class LoginFlow(FlowHandler[AuthFlowContext, AuthFlowResult, tuple[str, str]]):
|
||||||
"""Handler for the login flow."""
|
"""Handler for the login flow."""
|
||||||
|
|
||||||
_flow_result = AuthFlowResult
|
_flow_result = AuthFlowResult
|
||||||
|
|
|
@ -13,7 +13,7 @@ import voluptuous as vol
|
||||||
from homeassistant.const import CONF_COMMAND
|
from homeassistant.const import CONF_COMMAND
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from ..models import AuthFlowResult, Credentials, UserMeta
|
from ..models import AuthFlowContext, AuthFlowResult, Credentials, UserMeta
|
||||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||||
|
|
||||||
CONF_ARGS = "args"
|
CONF_ARGS = "args"
|
||||||
|
@ -59,7 +59,7 @@ class CommandLineAuthProvider(AuthProvider):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._user_meta: dict[str, dict[str, Any]] = {}
|
self._user_meta: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
async def async_login_flow(self, context: dict[str, Any] | None) -> LoginFlow:
|
async def async_login_flow(self, context: AuthFlowContext | None) -> LoginFlow:
|
||||||
"""Return a flow to login."""
|
"""Return a flow to login."""
|
||||||
return CommandLineLoginFlow(self)
|
return CommandLineLoginFlow(self)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.storage import Store
|
from homeassistant.helpers.storage import Store
|
||||||
|
|
||||||
from ..models import AuthFlowResult, Credentials, UserMeta
|
from ..models import AuthFlowContext, AuthFlowResult, Credentials, UserMeta
|
||||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||||
|
|
||||||
STORAGE_VERSION = 1
|
STORAGE_VERSION = 1
|
||||||
|
@ -305,7 +305,7 @@ class HassAuthProvider(AuthProvider):
|
||||||
await data.async_load()
|
await data.async_load()
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
async def async_login_flow(self, context: dict[str, Any] | None) -> LoginFlow:
|
async def async_login_flow(self, context: AuthFlowContext | None) -> LoginFlow:
|
||||||
"""Return a flow to login."""
|
"""Return a flow to login."""
|
||||||
return HassLoginFlow(self)
|
return HassLoginFlow(self)
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
import hmac
|
import hmac
|
||||||
from typing import Any, cast
|
from typing import cast
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from ..models import AuthFlowResult, Credentials, UserMeta
|
from ..models import AuthFlowContext, AuthFlowResult, Credentials, UserMeta
|
||||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||||
|
|
||||||
USER_SCHEMA = vol.Schema(
|
USER_SCHEMA = vol.Schema(
|
||||||
|
@ -36,7 +36,7 @@ class InvalidAuthError(HomeAssistantError):
|
||||||
class ExampleAuthProvider(AuthProvider):
|
class ExampleAuthProvider(AuthProvider):
|
||||||
"""Example auth provider based on hardcoded usernames and passwords."""
|
"""Example auth provider based on hardcoded usernames and passwords."""
|
||||||
|
|
||||||
async def async_login_flow(self, context: dict[str, Any] | None) -> LoginFlow:
|
async def async_login_flow(self, context: AuthFlowContext | None) -> LoginFlow:
|
||||||
"""Return a flow to login."""
|
"""Return a flow to login."""
|
||||||
return ExampleLoginFlow(self)
|
return ExampleLoginFlow(self)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,13 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.network import is_cloud_connection
|
from homeassistant.helpers.network import is_cloud_connection
|
||||||
|
|
||||||
from .. import InvalidAuthError
|
from .. import InvalidAuthError
|
||||||
from ..models import AuthFlowResult, Credentials, RefreshToken, UserMeta
|
from ..models import (
|
||||||
|
AuthFlowContext,
|
||||||
|
AuthFlowResult,
|
||||||
|
Credentials,
|
||||||
|
RefreshToken,
|
||||||
|
UserMeta,
|
||||||
|
)
|
||||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||||
|
|
||||||
type IPAddress = IPv4Address | IPv6Address
|
type IPAddress = IPv4Address | IPv6Address
|
||||||
|
@ -98,7 +104,7 @@ class TrustedNetworksAuthProvider(AuthProvider):
|
||||||
"""Trusted Networks auth provider does not support MFA."""
|
"""Trusted Networks auth provider does not support MFA."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def async_login_flow(self, context: dict[str, Any] | None) -> LoginFlow:
|
async def async_login_flow(self, context: AuthFlowContext | None) -> LoginFlow:
|
||||||
"""Return a flow to login."""
|
"""Return a flow to login."""
|
||||||
assert context is not None
|
assert context is not None
|
||||||
ip_addr = cast(IPAddress, context.get("ip_address"))
|
ip_addr = cast(IPAddress, context.get("ip_address"))
|
||||||
|
|
|
@ -9,6 +9,7 @@ import it.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
# pylint: disable-next=hass-deprecated-import
|
||||||
from functools import cached_property as _cached_property, partial
|
from functools import cached_property as _cached_property, partial
|
||||||
|
|
||||||
from homeassistant.helpers.deprecation import (
|
from homeassistant.helpers.deprecation import (
|
||||||
|
|
126
homeassistant/backup_restore.py
Normal file
126
homeassistant/backup_restore.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
"""Home Assistant module to handle restoring backups."""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
import securetar
|
||||||
|
|
||||||
|
from .const import __version__ as HA_VERSION
|
||||||
|
|
||||||
|
RESTORE_BACKUP_FILE = ".HA_RESTORE"
|
||||||
|
KEEP_PATHS = ("backups",)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RestoreBackupFileContent:
|
||||||
|
"""Definition for restore backup file content."""
|
||||||
|
|
||||||
|
backup_file_path: Path
|
||||||
|
|
||||||
|
|
||||||
|
def restore_backup_file_content(config_dir: Path) -> RestoreBackupFileContent | None:
|
||||||
|
"""Return the contents of the restore backup file."""
|
||||||
|
instruction_path = config_dir.joinpath(RESTORE_BACKUP_FILE)
|
||||||
|
try:
|
||||||
|
instruction_content = json.loads(instruction_path.read_text(encoding="utf-8"))
|
||||||
|
return RestoreBackupFileContent(
|
||||||
|
backup_file_path=Path(instruction_content["path"])
|
||||||
|
)
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _clear_configuration_directory(config_dir: Path) -> None:
|
||||||
|
"""Delete all files and directories in the config directory except for the backups directory."""
|
||||||
|
keep_paths = [config_dir.joinpath(path) for path in KEEP_PATHS]
|
||||||
|
config_contents = sorted(
|
||||||
|
[entry for entry in config_dir.iterdir() if entry not in keep_paths]
|
||||||
|
)
|
||||||
|
|
||||||
|
for entry in config_contents:
|
||||||
|
entrypath = config_dir.joinpath(entry)
|
||||||
|
|
||||||
|
if entrypath.is_file():
|
||||||
|
entrypath.unlink()
|
||||||
|
elif entrypath.is_dir():
|
||||||
|
shutil.rmtree(entrypath)
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_backup(config_dir: Path, backup_file_path: Path) -> None:
|
||||||
|
"""Extract the backup file to the config directory."""
|
||||||
|
with (
|
||||||
|
TemporaryDirectory() as tempdir,
|
||||||
|
securetar.SecureTarFile(
|
||||||
|
backup_file_path,
|
||||||
|
gzip=False,
|
||||||
|
mode="r",
|
||||||
|
) as ostf,
|
||||||
|
):
|
||||||
|
ostf.extractall(
|
||||||
|
path=Path(tempdir, "extracted"),
|
||||||
|
members=securetar.secure_path(ostf),
|
||||||
|
filter="fully_trusted",
|
||||||
|
)
|
||||||
|
backup_meta_file = Path(tempdir, "extracted", "backup.json")
|
||||||
|
backup_meta = json.loads(backup_meta_file.read_text(encoding="utf8"))
|
||||||
|
|
||||||
|
if (
|
||||||
|
backup_meta_version := AwesomeVersion(
|
||||||
|
backup_meta["homeassistant"]["version"]
|
||||||
|
)
|
||||||
|
) > HA_VERSION:
|
||||||
|
raise ValueError(
|
||||||
|
f"You need at least Home Assistant version {backup_meta_version} to restore this backup"
|
||||||
|
)
|
||||||
|
|
||||||
|
with securetar.SecureTarFile(
|
||||||
|
Path(
|
||||||
|
tempdir,
|
||||||
|
"extracted",
|
||||||
|
f"homeassistant.tar{'.gz' if backup_meta["compressed"] else ''}",
|
||||||
|
),
|
||||||
|
gzip=backup_meta["compressed"],
|
||||||
|
mode="r",
|
||||||
|
) as istf:
|
||||||
|
for member in istf.getmembers():
|
||||||
|
if member.name == "data":
|
||||||
|
continue
|
||||||
|
member.name = member.name.replace("data/", "")
|
||||||
|
_clear_configuration_directory(config_dir)
|
||||||
|
istf.extractall(
|
||||||
|
path=config_dir,
|
||||||
|
members=[
|
||||||
|
member
|
||||||
|
for member in securetar.secure_path(istf)
|
||||||
|
if member.name != "data"
|
||||||
|
],
|
||||||
|
filter="fully_trusted",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def restore_backup(config_dir_path: str) -> bool:
|
||||||
|
"""Restore the backup file if any.
|
||||||
|
|
||||||
|
Returns True if a restore backup file was found and restored, False otherwise.
|
||||||
|
"""
|
||||||
|
config_dir = Path(config_dir_path)
|
||||||
|
if not (restore_content := restore_backup_file_content(config_dir)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
||||||
|
backup_file_path = restore_content.backup_file_path
|
||||||
|
_LOGGER.info("Restoring %s", backup_file_path)
|
||||||
|
try:
|
||||||
|
_extract_backup(config_dir, backup_file_path)
|
||||||
|
except FileNotFoundError as err:
|
||||||
|
raise ValueError(f"Backup file {backup_file_path} does not exist") from err
|
||||||
|
_LOGGER.info("Restore complete, restarting")
|
||||||
|
return True
|
|
@ -8,6 +8,8 @@ import glob
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from ssl import SSLContext
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -143,6 +145,78 @@ _BLOCKING_CALLS: tuple[BlockingCall, ...] = (
|
||||||
strict_core=False,
|
strict_core=False,
|
||||||
skip_for_tests=True,
|
skip_for_tests=True,
|
||||||
),
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=SSLContext.load_default_certs,
|
||||||
|
object=SSLContext,
|
||||||
|
function="load_default_certs",
|
||||||
|
check_allowed=None,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=SSLContext.load_verify_locations,
|
||||||
|
object=SSLContext,
|
||||||
|
function="load_verify_locations",
|
||||||
|
check_allowed=None,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=SSLContext.load_cert_chain,
|
||||||
|
object=SSLContext,
|
||||||
|
function="load_cert_chain",
|
||||||
|
check_allowed=None,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=Path.open,
|
||||||
|
object=Path,
|
||||||
|
function="open",
|
||||||
|
check_allowed=_check_file_allowed,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=Path.read_text,
|
||||||
|
object=Path,
|
||||||
|
function="read_text",
|
||||||
|
check_allowed=_check_file_allowed,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=Path.read_bytes,
|
||||||
|
object=Path,
|
||||||
|
function="read_bytes",
|
||||||
|
check_allowed=_check_file_allowed,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=Path.write_text,
|
||||||
|
object=Path,
|
||||||
|
function="write_text",
|
||||||
|
check_allowed=_check_file_allowed,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
|
BlockingCall(
|
||||||
|
original_func=Path.write_bytes,
|
||||||
|
object=Path,
|
||||||
|
function="write_bytes",
|
||||||
|
check_allowed=_check_file_allowed,
|
||||||
|
strict=False,
|
||||||
|
strict_core=False,
|
||||||
|
skip_for_tests=True,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ from .const import (
|
||||||
REQUIRED_NEXT_PYTHON_VER,
|
REQUIRED_NEXT_PYTHON_VER,
|
||||||
SIGNAL_BOOTSTRAP_INTEGRATIONS,
|
SIGNAL_BOOTSTRAP_INTEGRATIONS,
|
||||||
)
|
)
|
||||||
|
from .core_config import async_process_ha_core_config
|
||||||
from .exceptions import HomeAssistantError
|
from .exceptions import HomeAssistantError
|
||||||
from .helpers import (
|
from .helpers import (
|
||||||
area_registry,
|
area_registry,
|
||||||
|
@ -479,7 +480,7 @@ async def async_from_config_dict(
|
||||||
core_config = config.get(core.DOMAIN, {})
|
core_config = config.get(core.DOMAIN, {})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await conf_util.async_process_ha_core_config(hass, core_config)
|
await async_process_ha_core_config(hass, core_config)
|
||||||
except vol.Invalid as config_err:
|
except vol.Invalid as config_err:
|
||||||
conf_util.async_log_schema_error(config_err, core.DOMAIN, core_config, hass)
|
conf_util.async_log_schema_error(config_err, core.DOMAIN, core_config, hass)
|
||||||
async_notify_setup_error(hass, core.DOMAIN)
|
async_notify_setup_error(hass, core.DOMAIN)
|
||||||
|
@ -514,7 +515,7 @@ async def async_from_config_dict(
|
||||||
issue_registry.async_create_issue(
|
issue_registry.async_create_issue(
|
||||||
hass,
|
hass,
|
||||||
core.DOMAIN,
|
core.DOMAIN,
|
||||||
"python_version",
|
f"python_version_{required_python_version}",
|
||||||
is_fixable=False,
|
is_fixable=False,
|
||||||
severity=issue_registry.IssueSeverity.WARNING,
|
severity=issue_registry.IssueSeverity.WARNING,
|
||||||
breaks_in_ha_version=REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
breaks_in_ha_version=REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||||
|
@ -586,10 +587,10 @@ async def async_enable_logging(
|
||||||
logging.getLogger("aiohttp.access").setLevel(logging.WARNING)
|
logging.getLogger("aiohttp.access").setLevel(logging.WARNING)
|
||||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||||
|
|
||||||
sys.excepthook = lambda *args: logging.getLogger(None).exception(
|
sys.excepthook = lambda *args: logging.getLogger().exception(
|
||||||
"Uncaught exception", exc_info=args
|
"Uncaught exception", exc_info=args
|
||||||
)
|
)
|
||||||
threading.excepthook = lambda args: logging.getLogger(None).exception(
|
threading.excepthook = lambda args: logging.getLogger().exception(
|
||||||
"Uncaught thread exception",
|
"Uncaught thread exception",
|
||||||
exc_info=( # type: ignore[arg-type]
|
exc_info=( # type: ignore[arg-type]
|
||||||
args.exc_type,
|
args.exc_type,
|
||||||
|
@ -616,10 +617,9 @@ async def async_enable_logging(
|
||||||
_create_log_file, err_log_path, log_rotate_days
|
_create_log_file, err_log_path, log_rotate_days
|
||||||
)
|
)
|
||||||
|
|
||||||
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
|
|
||||||
err_handler.setFormatter(logging.Formatter(fmt, datefmt=FORMAT_DATETIME))
|
err_handler.setFormatter(logging.Formatter(fmt, datefmt=FORMAT_DATETIME))
|
||||||
|
|
||||||
logger = logging.getLogger("")
|
logger = logging.getLogger()
|
||||||
logger.addHandler(err_handler)
|
logger.addHandler(err_handler)
|
||||||
logger.setLevel(logging.INFO if verbose else logging.WARNING)
|
logger.setLevel(logging.INFO if verbose else logging.WARNING)
|
||||||
|
|
||||||
|
|
5
homeassistant/brands/aqara.json
Normal file
5
homeassistant/brands/aqara.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"domain": "aqara",
|
||||||
|
"name": "Aqara",
|
||||||
|
"iot_standards": ["matter", "zigbee"]
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"domain": "asterisk",
|
|
||||||
"name": "Asterisk",
|
|
||||||
"integrations": ["asterisk_cdr", "asterisk_mbox"]
|
|
||||||
}
|
|
5
homeassistant/brands/fujitsu.json
Normal file
5
homeassistant/brands/fujitsu.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"domain": "fujitsu",
|
||||||
|
"name": "Fujitsu",
|
||||||
|
"integrations": ["fujitsu_anywair", "fujitsu_fglair"]
|
||||||
|
}
|
|
@ -5,10 +5,10 @@
|
||||||
"google_assistant",
|
"google_assistant",
|
||||||
"google_assistant_sdk",
|
"google_assistant_sdk",
|
||||||
"google_cloud",
|
"google_cloud",
|
||||||
"google_domains",
|
|
||||||
"google_generative_ai_conversation",
|
"google_generative_ai_conversation",
|
||||||
"google_mail",
|
"google_mail",
|
||||||
"google_maps",
|
"google_maps",
|
||||||
|
"google_photos",
|
||||||
"google_pubsub",
|
"google_pubsub",
|
||||||
"google_sheets",
|
"google_sheets",
|
||||||
"google_tasks",
|
"google_tasks",
|
||||||
|
|
5
homeassistant/brands/husqvarna.json
Normal file
5
homeassistant/brands/husqvarna.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"domain": "husqvarna",
|
||||||
|
"name": "Husqvarna",
|
||||||
|
"integrations": ["husqvarna_automower", "husqvarna_automower_ble"]
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"domain": "lg",
|
"domain": "lg",
|
||||||
"name": "LG",
|
"name": "LG",
|
||||||
"integrations": ["lg_netcast", "lg_soundbar", "webostv"]
|
"integrations": ["lg_netcast", "lg_soundbar", "lg_thinq", "webostv"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"domain": "logitech",
|
"domain": "logitech",
|
||||||
"name": "Logitech",
|
"name": "Logitech",
|
||||||
"integrations": ["harmony", "ue_smart_radio", "squeezebox"]
|
"integrations": ["harmony", "squeezebox"]
|
||||||
}
|
}
|
||||||
|
|
5
homeassistant/brands/roth.json
Normal file
5
homeassistant/brands/roth.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"domain": "roth",
|
||||||
|
"name": "Roth",
|
||||||
|
"integrations": ["touchline", "touchline_sl"]
|
||||||
|
}
|
5
homeassistant/brands/sky.json
Normal file
5
homeassistant/brands/sky.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"domain": "sky",
|
||||||
|
"name": "Sky",
|
||||||
|
"integrations": ["sky_hub", "sky_remote"]
|
||||||
|
}
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"domain": "yale",
|
"domain": "yale",
|
||||||
"name": "Yale",
|
"name": "Yale",
|
||||||
"integrations": ["august", "yale_smart_alarm", "yalexs_ble", "yale_home"]
|
"integrations": [
|
||||||
|
"august",
|
||||||
|
"yale_smart_alarm",
|
||||||
|
"yalexs_ble",
|
||||||
|
"yale_home",
|
||||||
|
"yale"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,52 +6,3 @@ Component design guidelines:
|
||||||
format "<DOMAIN>.<OBJECT_ID>".
|
format "<DOMAIN>.<OBJECT_ID>".
|
||||||
- Each component should publish services only under its own domain.
|
- Each component should publish services only under its own domain.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant, split_entity_id
|
|
||||||
from homeassistant.helpers.frame import report
|
|
||||||
from homeassistant.helpers.group import expand_entity_ids
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def is_on(hass: HomeAssistant, entity_id: str | None = None) -> bool:
|
|
||||||
"""Load up the module to call the is_on method.
|
|
||||||
|
|
||||||
If there is no entity id given we will check all.
|
|
||||||
"""
|
|
||||||
report(
|
|
||||||
(
|
|
||||||
"uses homeassistant.components.is_on."
|
|
||||||
" This is deprecated and will stop working in Home Assistant 2024.9, it"
|
|
||||||
" should be updated to use the function of the platform directly."
|
|
||||||
),
|
|
||||||
error_if_core=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if entity_id:
|
|
||||||
entity_ids = expand_entity_ids(hass, [entity_id])
|
|
||||||
else:
|
|
||||||
entity_ids = hass.states.entity_ids()
|
|
||||||
|
|
||||||
for ent_id in entity_ids:
|
|
||||||
domain = split_entity_id(ent_id)[0]
|
|
||||||
|
|
||||||
try:
|
|
||||||
component = getattr(hass.components, domain)
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
_LOGGER.error("Failed to call %s.is_on: component not found", domain)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not hasattr(component, "is_on"):
|
|
||||||
_LOGGER.warning("Integration %s has no is_on method", domain)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if component.is_on(ent_id):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
|
@ -4,8 +4,10 @@ from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from jaraco.abode.client import Client as Abode
|
from jaraco.abode.client import Client as Abode
|
||||||
|
import jaraco.abode.config
|
||||||
from jaraco.abode.exceptions import (
|
from jaraco.abode.exceptions import (
|
||||||
AuthenticationException as AbodeAuthenticationException,
|
AuthenticationException as AbodeAuthenticationException,
|
||||||
Exception as AbodeException,
|
Exception as AbodeException,
|
||||||
|
@ -93,6 +95,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
password = entry.data[CONF_PASSWORD]
|
password = entry.data[CONF_PASSWORD]
|
||||||
polling = entry.data[CONF_POLLING]
|
polling = entry.data[CONF_POLLING]
|
||||||
|
|
||||||
|
# Configure abode library to use config directory for storing data
|
||||||
|
jaraco.abode.config.paths.override(user_data=Path(hass.config.path("Abode")))
|
||||||
|
|
||||||
# For previous config entries where unique_id is None
|
# For previous config entries where unique_id is None
|
||||||
if entry.unique_id is None:
|
if entry.unique_id is None:
|
||||||
hass.config_entries.async_update_entry(
|
hass.config_entries.async_update_entry(
|
||||||
|
|
|
@ -7,13 +7,9 @@ from jaraco.abode.devices.alarm import Alarm
|
||||||
from homeassistant.components.alarm_control_panel import (
|
from homeassistant.components.alarm_control_panel import (
|
||||||
AlarmControlPanelEntity,
|
AlarmControlPanelEntity,
|
||||||
AlarmControlPanelEntityFeature,
|
AlarmControlPanelEntityFeature,
|
||||||
|
AlarmControlPanelState,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
|
||||||
STATE_ALARM_ARMED_AWAY,
|
|
||||||
STATE_ALARM_ARMED_HOME,
|
|
||||||
STATE_ALARM_DISARMED,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
@ -44,14 +40,14 @@ class AbodeAlarm(AbodeDevice, AlarmControlPanelEntity):
|
||||||
_device: Alarm
|
_device: Alarm
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> str | None:
|
def alarm_state(self) -> AlarmControlPanelState | None:
|
||||||
"""Return the state of the device."""
|
"""Return the state of the device."""
|
||||||
if self._device.is_standby:
|
if self._device.is_standby:
|
||||||
return STATE_ALARM_DISARMED
|
return AlarmControlPanelState.DISARMED
|
||||||
if self._device.is_away:
|
if self._device.is_away:
|
||||||
return STATE_ALARM_ARMED_AWAY
|
return AlarmControlPanelState.ARMED_AWAY
|
||||||
if self._device.is_home:
|
if self._device.is_home:
|
||||||
return STATE_ALARM_ARMED_HOME
|
return AlarmControlPanelState.ARMED_HOME
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def alarm_disarm(self, code: str | None = None) -> None:
|
def alarm_disarm(self, code: str | None = None) -> None:
|
||||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from jaraco.abode.devices.sensor import BinarySensor
|
from jaraco.abode.devices.binary_sensor import BinarySensor
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
BinarySensorDeviceClass,
|
BinarySensorDeviceClass,
|
||||||
|
|
|
@ -102,15 +102,7 @@ class AbodeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
existing_entry = await self.async_set_unique_id(self._username)
|
existing_entry = await self.async_set_unique_id(self._username)
|
||||||
|
|
||||||
if existing_entry:
|
if existing_entry:
|
||||||
self.hass.config_entries.async_update_entry(
|
return self.async_update_reload_and_abort(existing_entry, data=config_data)
|
||||||
existing_entry, data=config_data
|
|
||||||
)
|
|
||||||
# Reload the Abode config entry otherwise devices will remain unavailable
|
|
||||||
self.hass.async_create_task(
|
|
||||||
self.hass.config_entries.async_reload(existing_entry.entry_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.async_abort(reason="reauth_successful")
|
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=cast(str, self._username), data=config_data
|
title=cast(str, self._username), data=config_data
|
||||||
|
|
|
@ -7,8 +7,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"capture_image": "mdi:camera",
|
"capture_image": {
|
||||||
"change_setting": "mdi:cog",
|
"service": "mdi:camera"
|
||||||
"trigger_automation": "mdi:play"
|
},
|
||||||
|
"change_setting": {
|
||||||
|
"service": "mdi:cog"
|
||||||
|
},
|
||||||
|
"trigger_automation": {
|
||||||
|
"service": "mdi:play"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
},
|
},
|
||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"loggers": ["jaraco.abode", "lomond"],
|
"loggers": ["jaraco.abode", "lomond"],
|
||||||
"requirements": ["jaraco.abode==5.2.1"]
|
"requirements": ["jaraco.abode==6.2.1"]
|
||||||
}
|
}
|
||||||
|
|
29
homeassistant/components/acaia/__init__.py
Normal file
29
homeassistant/components/acaia/__init__.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
"""Initialize the Acaia component."""
|
||||||
|
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .coordinator import AcaiaConfigEntry, AcaiaCoordinator
|
||||||
|
|
||||||
|
PLATFORMS = [
|
||||||
|
Platform.BUTTON,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: AcaiaConfigEntry) -> bool:
|
||||||
|
"""Set up acaia as config entry."""
|
||||||
|
|
||||||
|
coordinator = AcaiaCoordinator(hass, entry)
|
||||||
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
|
entry.runtime_data = coordinator
|
||||||
|
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, entry: AcaiaConfigEntry) -> bool:
|
||||||
|
"""Unload a config entry."""
|
||||||
|
|
||||||
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
61
homeassistant/components/acaia/button.py
Normal file
61
homeassistant/components/acaia/button.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
"""Button entities for Acaia scales."""
|
||||||
|
|
||||||
|
from collections.abc import Callable, Coroutine
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from aioacaia.acaiascale import AcaiaScale
|
||||||
|
|
||||||
|
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .coordinator import AcaiaConfigEntry
|
||||||
|
from .entity import AcaiaEntity
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(kw_only=True, frozen=True)
|
||||||
|
class AcaiaButtonEntityDescription(ButtonEntityDescription):
|
||||||
|
"""Description for acaia button entities."""
|
||||||
|
|
||||||
|
press_fn: Callable[[AcaiaScale], Coroutine[Any, Any, None]]
|
||||||
|
|
||||||
|
|
||||||
|
BUTTONS: tuple[AcaiaButtonEntityDescription, ...] = (
|
||||||
|
AcaiaButtonEntityDescription(
|
||||||
|
key="tare",
|
||||||
|
translation_key="tare",
|
||||||
|
press_fn=lambda scale: scale.tare(),
|
||||||
|
),
|
||||||
|
AcaiaButtonEntityDescription(
|
||||||
|
key="reset_timer",
|
||||||
|
translation_key="reset_timer",
|
||||||
|
press_fn=lambda scale: scale.reset_timer(),
|
||||||
|
),
|
||||||
|
AcaiaButtonEntityDescription(
|
||||||
|
key="start_stop",
|
||||||
|
translation_key="start_stop",
|
||||||
|
press_fn=lambda scale: scale.start_stop_timer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: AcaiaConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up button entities and services."""
|
||||||
|
|
||||||
|
coordinator = entry.runtime_data
|
||||||
|
async_add_entities(AcaiaButton(coordinator, description) for description in BUTTONS)
|
||||||
|
|
||||||
|
|
||||||
|
class AcaiaButton(AcaiaEntity, ButtonEntity):
|
||||||
|
"""Representation of an Acaia button."""
|
||||||
|
|
||||||
|
entity_description: AcaiaButtonEntityDescription
|
||||||
|
|
||||||
|
async def async_press(self) -> None:
|
||||||
|
"""Handle the button press."""
|
||||||
|
await self.entity_description.press_fn(self._scale)
|
149
homeassistant/components/acaia/config_flow.py
Normal file
149
homeassistant/components/acaia/config_flow.py
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
"""Config flow for Acaia integration."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from aioacaia.exceptions import AcaiaDeviceNotFound, AcaiaError, AcaiaUnknownDevice
|
||||||
|
from aioacaia.helpers import is_new_scale
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.bluetooth import (
|
||||||
|
BluetoothServiceInfoBleak,
|
||||||
|
async_discovered_service_info,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
|
from homeassistant.const import CONF_ADDRESS, CONF_NAME
|
||||||
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
|
from homeassistant.helpers.selector import (
|
||||||
|
SelectOptionDict,
|
||||||
|
SelectSelector,
|
||||||
|
SelectSelectorConfig,
|
||||||
|
SelectSelectorMode,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .const import CONF_IS_NEW_STYLE_SCALE, DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AcaiaConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Handle a config flow for acaia."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Initialize the config flow."""
|
||||||
|
self._discovered: dict[str, Any] = {}
|
||||||
|
self._discovered_devices: dict[str, str] = {}
|
||||||
|
|
||||||
|
async def async_step_user(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle a flow initialized by the user."""
|
||||||
|
|
||||||
|
errors: dict[str, str] = {}
|
||||||
|
|
||||||
|
if user_input is not None:
|
||||||
|
mac = format_mac(user_input[CONF_ADDRESS])
|
||||||
|
try:
|
||||||
|
is_new_style_scale = await is_new_scale(mac)
|
||||||
|
except AcaiaDeviceNotFound:
|
||||||
|
errors["base"] = "device_not_found"
|
||||||
|
except AcaiaError:
|
||||||
|
_LOGGER.exception("Error occurred while connecting to the scale")
|
||||||
|
errors["base"] = "unknown"
|
||||||
|
except AcaiaUnknownDevice:
|
||||||
|
return self.async_abort(reason="unsupported_device")
|
||||||
|
else:
|
||||||
|
await self.async_set_unique_id(mac)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
|
if not errors:
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=self._discovered_devices[user_input[CONF_ADDRESS]],
|
||||||
|
data={
|
||||||
|
CONF_ADDRESS: mac,
|
||||||
|
CONF_IS_NEW_STYLE_SCALE: is_new_style_scale,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
for device in async_discovered_service_info(self.hass):
|
||||||
|
self._discovered_devices[device.address] = device.name
|
||||||
|
|
||||||
|
if not self._discovered_devices:
|
||||||
|
return self.async_abort(reason="no_devices_found")
|
||||||
|
|
||||||
|
options = [
|
||||||
|
SelectOptionDict(
|
||||||
|
value=device_mac,
|
||||||
|
label=f"{device_name} ({device_mac})",
|
||||||
|
)
|
||||||
|
for device_mac, device_name in self._discovered_devices.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ADDRESS): SelectSelector(
|
||||||
|
SelectSelectorConfig(
|
||||||
|
options=options,
|
||||||
|
mode=SelectSelectorMode.DROPDOWN,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
errors=errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_bluetooth(
|
||||||
|
self, discovery_info: BluetoothServiceInfoBleak
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle a discovered Bluetooth device."""
|
||||||
|
|
||||||
|
self._discovered[CONF_ADDRESS] = mac = format_mac(discovery_info.address)
|
||||||
|
self._discovered[CONF_NAME] = discovery_info.name
|
||||||
|
|
||||||
|
await self.async_set_unique_id(mac)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._discovered[CONF_IS_NEW_STYLE_SCALE] = await is_new_scale(
|
||||||
|
discovery_info.address
|
||||||
|
)
|
||||||
|
except AcaiaDeviceNotFound:
|
||||||
|
_LOGGER.debug("Device not found during discovery")
|
||||||
|
return self.async_abort(reason="device_not_found")
|
||||||
|
except AcaiaError:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Error occurred while connecting to the scale during discovery",
|
||||||
|
exc_info=True,
|
||||||
|
)
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
except AcaiaUnknownDevice:
|
||||||
|
_LOGGER.debug("Unsupported device during discovery")
|
||||||
|
return self.async_abort(reason="unsupported_device")
|
||||||
|
|
||||||
|
return await self.async_step_bluetooth_confirm()
|
||||||
|
|
||||||
|
async def async_step_bluetooth_confirm(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle confirmation of Bluetooth discovery."""
|
||||||
|
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=self._discovered[CONF_NAME],
|
||||||
|
data={
|
||||||
|
CONF_ADDRESS: self._discovered[CONF_ADDRESS],
|
||||||
|
CONF_IS_NEW_STYLE_SCALE: self._discovered[CONF_IS_NEW_STYLE_SCALE],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.context["title_placeholders"] = placeholders = {
|
||||||
|
CONF_NAME: self._discovered[CONF_NAME]
|
||||||
|
}
|
||||||
|
|
||||||
|
self._set_confirm_only()
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="bluetooth_confirm",
|
||||||
|
description_placeholders=placeholders,
|
||||||
|
)
|
4
homeassistant/components/acaia/const.py
Normal file
4
homeassistant/components/acaia/const.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""Constants for component."""
|
||||||
|
|
||||||
|
DOMAIN = "acaia"
|
||||||
|
CONF_IS_NEW_STYLE_SCALE = "is_new_style_scale"
|
86
homeassistant/components/acaia/coordinator.py
Normal file
86
homeassistant/components/acaia/coordinator.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
"""Coordinator for Acaia integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from aioacaia.acaiascale import AcaiaScale
|
||||||
|
from aioacaia.exceptions import AcaiaDeviceNotFound, AcaiaError
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import CONF_ADDRESS
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
|
from .const import CONF_IS_NEW_STYLE_SCALE
|
||||||
|
|
||||||
|
SCAN_INTERVAL = timedelta(seconds=15)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
type AcaiaConfigEntry = ConfigEntry[AcaiaCoordinator]
|
||||||
|
|
||||||
|
|
||||||
|
class AcaiaCoordinator(DataUpdateCoordinator[None]):
|
||||||
|
"""Class to handle fetching data from the scale."""
|
||||||
|
|
||||||
|
config_entry: AcaiaConfigEntry
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, entry: AcaiaConfigEntry) -> None:
|
||||||
|
"""Initialize coordinator."""
|
||||||
|
super().__init__(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name="acaia coordinator",
|
||||||
|
update_interval=SCAN_INTERVAL,
|
||||||
|
config_entry=entry,
|
||||||
|
)
|
||||||
|
|
||||||
|
self._scale = AcaiaScale(
|
||||||
|
address_or_ble_device=entry.data[CONF_ADDRESS],
|
||||||
|
name=entry.title,
|
||||||
|
is_new_style_scale=entry.data[CONF_IS_NEW_STYLE_SCALE],
|
||||||
|
notify_callback=self.async_update_listeners,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scale(self) -> AcaiaScale:
|
||||||
|
"""Return the scale object."""
|
||||||
|
return self._scale
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> None:
|
||||||
|
"""Fetch data."""
|
||||||
|
|
||||||
|
# scale is already connected, return
|
||||||
|
if self._scale.connected:
|
||||||
|
return
|
||||||
|
|
||||||
|
# scale is not connected, try to connect
|
||||||
|
try:
|
||||||
|
await self._scale.connect(setup_tasks=False)
|
||||||
|
except (AcaiaDeviceNotFound, AcaiaError, TimeoutError) as ex:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Could not connect to scale: %s, Error: %s",
|
||||||
|
self.config_entry.data[CONF_ADDRESS],
|
||||||
|
ex,
|
||||||
|
)
|
||||||
|
self._scale.device_disconnected_handler(notify=False)
|
||||||
|
return
|
||||||
|
|
||||||
|
# connected, set up background tasks
|
||||||
|
if not self._scale.heartbeat_task or self._scale.heartbeat_task.done():
|
||||||
|
self._scale.heartbeat_task = self.config_entry.async_create_background_task(
|
||||||
|
hass=self.hass,
|
||||||
|
target=self._scale.send_heartbeats(),
|
||||||
|
name="acaia_heartbeat_task",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self._scale.process_queue_task or self._scale.process_queue_task.done():
|
||||||
|
self._scale.process_queue_task = (
|
||||||
|
self.config_entry.async_create_background_task(
|
||||||
|
hass=self.hass,
|
||||||
|
target=self._scale.process_queue(),
|
||||||
|
name="acaia_process_queue_task",
|
||||||
|
)
|
||||||
|
)
|
40
homeassistant/components/acaia/entity.py
Normal file
40
homeassistant/components/acaia/entity.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
"""Base class for Acaia entities."""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .coordinator import AcaiaCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AcaiaEntity(CoordinatorEntity[AcaiaCoordinator]):
|
||||||
|
"""Common elements for all entities."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: AcaiaCoordinator,
|
||||||
|
entity_description: EntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the entity."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = entity_description
|
||||||
|
self._scale = coordinator.scale
|
||||||
|
self._attr_unique_id = f"{self._scale.mac}_{entity_description.key}"
|
||||||
|
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, self._scale.mac)},
|
||||||
|
manufacturer="Acaia",
|
||||||
|
model=self._scale.model,
|
||||||
|
suggested_area="Kitchen",
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Returns whether entity is available."""
|
||||||
|
return super().available and self._scale.connected
|
15
homeassistant/components/acaia/icons.json
Normal file
15
homeassistant/components/acaia/icons.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"entity": {
|
||||||
|
"button": {
|
||||||
|
"tare": {
|
||||||
|
"default": "mdi:scale-balance"
|
||||||
|
},
|
||||||
|
"reset_timer": {
|
||||||
|
"default": "mdi:timer-refresh"
|
||||||
|
},
|
||||||
|
"start_stop": {
|
||||||
|
"default": "mdi:timer-play"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
homeassistant/components/acaia/manifest.json
Normal file
29
homeassistant/components/acaia/manifest.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"domain": "acaia",
|
||||||
|
"name": "Acaia",
|
||||||
|
"bluetooth": [
|
||||||
|
{
|
||||||
|
"manufacturer_id": 16962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"local_name": "ACAIA*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"local_name": "PYXIS-*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"local_name": "LUNAR-*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"local_name": "PROCHBT001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"codeowners": ["@zweckj"],
|
||||||
|
"config_flow": true,
|
||||||
|
"dependencies": ["bluetooth_adapters"],
|
||||||
|
"documentation": "https://www.home-assistant.io/integrations/acaia",
|
||||||
|
"integration_type": "device",
|
||||||
|
"iot_class": "local_push",
|
||||||
|
"loggers": ["aioacaia"],
|
||||||
|
"requirements": ["aioacaia==0.1.6"]
|
||||||
|
}
|
38
homeassistant/components/acaia/strings.json
Normal file
38
homeassistant/components/acaia/strings.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"flow_title": "{name}",
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||||
|
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
|
||||||
|
"unsupported_device": "This device is not supported."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"device_not_found": "Device could not be found.",
|
||||||
|
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"bluetooth_confirm": {
|
||||||
|
"description": "[%key:component::bluetooth::config::step::bluetooth_confirm::description%]"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"description": "[%key:component::bluetooth::config::step::user::description%]",
|
||||||
|
"data": {
|
||||||
|
"address": "[%key:common::config_flow::data::device%]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"button": {
|
||||||
|
"tare": {
|
||||||
|
"name": "Tare"
|
||||||
|
},
|
||||||
|
"reset_timer": {
|
||||||
|
"name": "Reset timer"
|
||||||
|
},
|
||||||
|
"start_stop": {
|
||||||
|
"name": "Start/stop timer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from accuweather import AccuWeather
|
from accuweather import AccuWeather
|
||||||
|
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_PLATFORM
|
from homeassistant.components.sensor import DOMAIN as SENSOR_PLATFORM
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import CONF_API_KEY, CONF_NAME, Platform
|
from homeassistant.const import CONF_API_KEY, CONF_NAME, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
@ -16,7 +14,9 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .const import DOMAIN, UPDATE_INTERVAL_DAILY_FORECAST, UPDATE_INTERVAL_OBSERVATION
|
from .const import DOMAIN, UPDATE_INTERVAL_DAILY_FORECAST, UPDATE_INTERVAL_OBSERVATION
|
||||||
from .coordinator import (
|
from .coordinator import (
|
||||||
|
AccuWeatherConfigEntry,
|
||||||
AccuWeatherDailyForecastDataUpdateCoordinator,
|
AccuWeatherDailyForecastDataUpdateCoordinator,
|
||||||
|
AccuWeatherData,
|
||||||
AccuWeatherObservationDataUpdateCoordinator,
|
AccuWeatherObservationDataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,17 +25,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class AccuWeatherData:
|
|
||||||
"""Data for AccuWeather integration."""
|
|
||||||
|
|
||||||
coordinator_observation: AccuWeatherObservationDataUpdateCoordinator
|
|
||||||
coordinator_daily_forecast: AccuWeatherDailyForecastDataUpdateCoordinator
|
|
||||||
|
|
||||||
|
|
||||||
type AccuWeatherConfigEntry = ConfigEntry[AccuWeatherData]
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry) -> bool:
|
||||||
"""Set up AccuWeather as config entry."""
|
"""Set up AccuWeather as config entry."""
|
||||||
api_key: str = entry.data[CONF_API_KEY]
|
api_key: str = entry.data[CONF_API_KEY]
|
||||||
|
@ -50,6 +39,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry)
|
||||||
|
|
||||||
coordinator_observation = AccuWeatherObservationDataUpdateCoordinator(
|
coordinator_observation = AccuWeatherObservationDataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
|
entry,
|
||||||
accuweather,
|
accuweather,
|
||||||
name,
|
name,
|
||||||
"observation",
|
"observation",
|
||||||
|
@ -58,6 +48,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry)
|
||||||
|
|
||||||
coordinator_daily_forecast = AccuWeatherDailyForecastDataUpdateCoordinator(
|
coordinator_daily_forecast = AccuWeatherDailyForecastDataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
|
entry,
|
||||||
accuweather,
|
accuweather,
|
||||||
name,
|
name,
|
||||||
"daily forecast",
|
"daily forecast",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
"""The AccuWeather coordinator."""
|
"""The AccuWeather coordinator."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from asyncio import timeout
|
from asyncio import timeout
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
@ -8,6 +11,7 @@ from typing import TYPE_CHECKING, Any
|
||||||
from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExceededError
|
from accuweather import AccuWeather, ApiError, InvalidApiKeyError, RequestsExceededError
|
||||||
from aiohttp.client_exceptions import ClientConnectorError
|
from aiohttp.client_exceptions import ClientConnectorError
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
@ -23,6 +27,17 @@ EXCEPTIONS = (ApiError, ClientConnectorError, InvalidApiKeyError, RequestsExceed
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AccuWeatherData:
|
||||||
|
"""Data for AccuWeather integration."""
|
||||||
|
|
||||||
|
coordinator_observation: AccuWeatherObservationDataUpdateCoordinator
|
||||||
|
coordinator_daily_forecast: AccuWeatherDailyForecastDataUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
type AccuWeatherConfigEntry = ConfigEntry[AccuWeatherData]
|
||||||
|
|
||||||
|
|
||||||
class AccuWeatherObservationDataUpdateCoordinator(
|
class AccuWeatherObservationDataUpdateCoordinator(
|
||||||
DataUpdateCoordinator[dict[str, Any]]
|
DataUpdateCoordinator[dict[str, Any]]
|
||||||
):
|
):
|
||||||
|
@ -31,6 +46,7 @@ class AccuWeatherObservationDataUpdateCoordinator(
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
config_entry: AccuWeatherConfigEntry,
|
||||||
accuweather: AccuWeather,
|
accuweather: AccuWeather,
|
||||||
name: str,
|
name: str,
|
||||||
coordinator_type: str,
|
coordinator_type: str,
|
||||||
|
@ -48,6 +64,7 @@ class AccuWeatherObservationDataUpdateCoordinator(
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
|
config_entry=config_entry,
|
||||||
name=f"{name} ({coordinator_type})",
|
name=f"{name} ({coordinator_type})",
|
||||||
update_interval=update_interval,
|
update_interval=update_interval,
|
||||||
)
|
)
|
||||||
|
@ -73,6 +90,7 @@ class AccuWeatherDailyForecastDataUpdateCoordinator(
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
config_entry: AccuWeatherConfigEntry,
|
||||||
accuweather: AccuWeather,
|
accuweather: AccuWeather,
|
||||||
name: str,
|
name: str,
|
||||||
coordinator_type: str,
|
coordinator_type: str,
|
||||||
|
@ -90,6 +108,7 @@ class AccuWeatherDailyForecastDataUpdateCoordinator(
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
|
config_entry=config_entry,
|
||||||
name=f"{name} ({coordinator_type})",
|
name=f"{name} ({coordinator_type})",
|
||||||
update_interval=update_interval,
|
update_interval=update_interval,
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE
|
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import AccuWeatherConfigEntry, AccuWeatherData
|
from .coordinator import AccuWeatherConfigEntry, AccuWeatherData
|
||||||
|
|
||||||
TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE}
|
TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ from homeassistant.const import (
|
||||||
UV_INDEX,
|
UV_INDEX,
|
||||||
UnitOfIrradiance,
|
UnitOfIrradiance,
|
||||||
UnitOfLength,
|
UnitOfLength,
|
||||||
|
UnitOfPressure,
|
||||||
UnitOfSpeed,
|
UnitOfSpeed,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
UnitOfTime,
|
UnitOfTime,
|
||||||
|
@ -27,7 +28,6 @@ from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from . import AccuWeatherConfigEntry
|
|
||||||
from .const import (
|
from .const import (
|
||||||
API_METRIC,
|
API_METRIC,
|
||||||
ATTR_CATEGORY,
|
ATTR_CATEGORY,
|
||||||
|
@ -40,6 +40,7 @@ from .const import (
|
||||||
MAX_FORECAST_DAYS,
|
MAX_FORECAST_DAYS,
|
||||||
)
|
)
|
||||||
from .coordinator import (
|
from .coordinator import (
|
||||||
|
AccuWeatherConfigEntry,
|
||||||
AccuWeatherDailyForecastDataUpdateCoordinator,
|
AccuWeatherDailyForecastDataUpdateCoordinator,
|
||||||
AccuWeatherObservationDataUpdateCoordinator,
|
AccuWeatherObservationDataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
@ -279,6 +280,15 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||||
value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
|
value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
|
||||||
translation_key="realfeel_temperature_shade",
|
translation_key="realfeel_temperature_shade",
|
||||||
),
|
),
|
||||||
|
AccuWeatherSensorDescription(
|
||||||
|
key="RelativeHumidity",
|
||||||
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
value_fn=lambda data: cast(int, data),
|
||||||
|
translation_key="humidity",
|
||||||
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="Precipitation",
|
key="Precipitation",
|
||||||
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
|
@ -288,6 +298,16 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||||
attr_fn=lambda data: {"type": data["PrecipitationType"]},
|
attr_fn=lambda data: {"type": data["PrecipitationType"]},
|
||||||
translation_key="precipitation",
|
translation_key="precipitation",
|
||||||
),
|
),
|
||||||
|
AccuWeatherSensorDescription(
|
||||||
|
key="Pressure",
|
||||||
|
device_class=SensorDeviceClass.PRESSURE,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
native_unit_of_measurement=UnitOfPressure.HPA,
|
||||||
|
value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
|
||||||
|
translation_key="pressure",
|
||||||
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="PressureTendency",
|
key="PressureTendency",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
@ -295,9 +315,19 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||||
value_fn=lambda data: cast(str, data["LocalizedText"]).lower(),
|
value_fn=lambda data: cast(str, data["LocalizedText"]).lower(),
|
||||||
translation_key="pressure_tendency",
|
translation_key="pressure_tendency",
|
||||||
),
|
),
|
||||||
|
AccuWeatherSensorDescription(
|
||||||
|
key="Temperature",
|
||||||
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
|
value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
|
||||||
|
translation_key="temperature",
|
||||||
|
),
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="UVIndex",
|
key="UVIndex",
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
native_unit_of_measurement=UV_INDEX,
|
native_unit_of_measurement=UV_INDEX,
|
||||||
value_fn=lambda data: cast(int, data),
|
value_fn=lambda data: cast(int, data),
|
||||||
attr_fn=lambda data: {ATTR_LEVEL: data["UVIndexText"]},
|
attr_fn=lambda data: {ATTR_LEVEL: data["UVIndexText"]},
|
||||||
|
@ -324,6 +354,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
|
||||||
AccuWeatherSensorDescription(
|
AccuWeatherSensorDescription(
|
||||||
key="Wind",
|
key="Wind",
|
||||||
device_class=SensorDeviceClass.WIND_SPEED,
|
device_class=SensorDeviceClass.WIND_SPEED,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||||
value_fn=lambda data: cast(float, data[ATTR_SPEED][API_METRIC][ATTR_VALUE]),
|
value_fn=lambda data: cast(float, data[ATTR_SPEED][API_METRIC][ATTR_VALUE]),
|
||||||
|
|
|
@ -9,8 +9,8 @@ from accuweather.const import ENDPOINT
|
||||||
from homeassistant.components import system_health
|
from homeassistant.components import system_health
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
from . import AccuWeatherConfigEntry
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
from .coordinator import AccuWeatherConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
|
|
@ -33,7 +33,6 @@ from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.util.dt import utc_from_timestamp
|
from homeassistant.util.dt import utc_from_timestamp
|
||||||
|
|
||||||
from . import AccuWeatherConfigEntry, AccuWeatherData
|
|
||||||
from .const import (
|
from .const import (
|
||||||
API_METRIC,
|
API_METRIC,
|
||||||
ATTR_DIRECTION,
|
ATTR_DIRECTION,
|
||||||
|
@ -43,7 +42,9 @@ from .const import (
|
||||||
CONDITION_MAP,
|
CONDITION_MAP,
|
||||||
)
|
)
|
||||||
from .coordinator import (
|
from .coordinator import (
|
||||||
|
AccuWeatherConfigEntry,
|
||||||
AccuWeatherDailyForecastDataUpdateCoordinator,
|
AccuWeatherDailyForecastDataUpdateCoordinator,
|
||||||
|
AccuWeatherData,
|
||||||
AccuWeatherObservationDataUpdateCoordinator,
|
AccuWeatherObservationDataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ class AcerSwitch(SwitchEntity):
|
||||||
write_timeout: int,
|
write_timeout: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init of the Acer projector."""
|
"""Init of the Acer projector."""
|
||||||
self.ser = serial.Serial(
|
self.serial = serial.Serial(
|
||||||
port=serial_port, timeout=timeout, write_timeout=write_timeout
|
port=serial_port, timeout=timeout, write_timeout=write_timeout
|
||||||
)
|
)
|
||||||
self._serial_port = serial_port
|
self._serial_port = serial_port
|
||||||
|
@ -99,16 +99,16 @@ class AcerSwitch(SwitchEntity):
|
||||||
# was disconnected during runtime.
|
# was disconnected during runtime.
|
||||||
# This way the projector can be reconnected and will still work
|
# This way the projector can be reconnected and will still work
|
||||||
try:
|
try:
|
||||||
if not self.ser.is_open:
|
if not self.serial.is_open:
|
||||||
self.ser.open()
|
self.serial.open()
|
||||||
self.ser.write(msg.encode("utf-8"))
|
self.serial.write(msg.encode("utf-8"))
|
||||||
# Size is an experience value there is no real limit.
|
# Size is an experience value there is no real limit.
|
||||||
# AFAIK there is no limit and no end character so we will usually
|
# AFAIK there is no limit and no end character so we will usually
|
||||||
# need to wait for timeout
|
# need to wait for timeout
|
||||||
ret = self.ser.read_until(size=20).decode("utf-8")
|
ret = self.serial.read_until(size=20).decode("utf-8")
|
||||||
except serial.SerialException:
|
except serial.SerialException:
|
||||||
_LOGGER.error("Problem communicating with %s", self._serial_port)
|
_LOGGER.error("Problem communicating with %s", self._serial_port)
|
||||||
self.ser.close()
|
self.serial.close()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _write_read_format(self, msg: str) -> str:
|
def _write_read_format(self, msg: str) -> str:
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
import homeassistant.helpers.entity_registry as er
|
||||||
|
|
||||||
from .hub import PulseHub
|
from .hub import PulseHub
|
||||||
|
|
||||||
|
@ -17,6 +18,9 @@ async def async_setup_entry(
|
||||||
hass: HomeAssistant, config_entry: AcmedaConfigEntry
|
hass: HomeAssistant, config_entry: AcmedaConfigEntry
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Set up Rollease Acmeda Automate hub from a config entry."""
|
"""Set up Rollease Acmeda Automate hub from a config entry."""
|
||||||
|
|
||||||
|
await _migrate_unique_ids(hass, config_entry)
|
||||||
|
|
||||||
hub = PulseHub(hass, config_entry)
|
hub = PulseHub(hass, config_entry)
|
||||||
|
|
||||||
if not await hub.async_setup():
|
if not await hub.async_setup():
|
||||||
|
@ -28,6 +32,19 @@ async def async_setup_entry(
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def _migrate_unique_ids(hass: HomeAssistant, entry: AcmedaConfigEntry) -> None:
|
||||||
|
"""Migrate pre-config flow unique ids."""
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
registry_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, entry.entry_id
|
||||||
|
)
|
||||||
|
for reg_entry in registry_entries:
|
||||||
|
if isinstance(reg_entry.unique_id, int): # type: ignore[unreachable]
|
||||||
|
entity_registry.async_update_entity( # type: ignore[unreachable]
|
||||||
|
reg_entry.entity_id, new_unique_id=str(reg_entry.unique_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(
|
async def async_unload_entry(
|
||||||
hass: HomeAssistant, config_entry: AcmedaConfigEntry
|
hass: HomeAssistant, config_entry: AcmedaConfigEntry
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
|
@ -14,8 +14,8 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import AcmedaConfigEntry
|
from . import AcmedaConfigEntry
|
||||||
from .base import AcmedaBase
|
|
||||||
from .const import ACMEDA_HUB_UPDATE
|
from .const import ACMEDA_HUB_UPDATE
|
||||||
|
from .entity import AcmedaEntity
|
||||||
from .helpers import async_add_acmeda_entities
|
from .helpers import async_add_acmeda_entities
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AcmedaCover(AcmedaBase, CoverEntity):
|
class AcmedaCover(AcmedaEntity, CoverEntity):
|
||||||
"""Representation of an Acmeda cover device."""
|
"""Representation of an Acmeda cover device."""
|
||||||
|
|
||||||
_attr_name = None
|
_attr_name = None
|
||||||
|
|
|
@ -11,7 +11,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from .const import ACMEDA_ENTITY_REMOVE, DOMAIN, LOGGER
|
from .const import ACMEDA_ENTITY_REMOVE, DOMAIN, LOGGER
|
||||||
|
|
||||||
|
|
||||||
class AcmedaBase(entity.Entity):
|
class AcmedaEntity(entity.Entity):
|
||||||
"""Base representation of an Acmeda roller."""
|
"""Base representation of an Acmeda roller."""
|
||||||
|
|
||||||
_attr_should_poll = False
|
_attr_should_poll = False
|
||||||
|
@ -67,7 +67,7 @@ class AcmedaBase(entity.Entity):
|
||||||
@property
|
@property
|
||||||
def unique_id(self) -> str:
|
def unique_id(self) -> str:
|
||||||
"""Return the unique ID of this roller."""
|
"""Return the unique ID of this roller."""
|
||||||
return self.roller.id # type: ignore[no-any-return]
|
return str(self.roller.id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_id(self) -> str:
|
def device_id(self) -> str:
|
|
@ -6,5 +6,5 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/acmeda",
|
"documentation": "https://www.home-assistant.io/integrations/acmeda",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["aiopulse"],
|
"loggers": ["aiopulse"],
|
||||||
"requirements": ["aiopulse==0.4.4"]
|
"requirements": ["aiopulse==0.4.6"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import AcmedaConfigEntry
|
from . import AcmedaConfigEntry
|
||||||
from .base import AcmedaBase
|
|
||||||
from .const import ACMEDA_HUB_UPDATE
|
from .const import ACMEDA_HUB_UPDATE
|
||||||
|
from .entity import AcmedaEntity
|
||||||
from .helpers import async_add_acmeda_entities
|
from .helpers import async_add_acmeda_entities
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AcmedaBattery(AcmedaBase, SensorEntity):
|
class AcmedaBattery(AcmedaEntity, SensorEntity):
|
||||||
"""Representation of an Acmeda cover sensor."""
|
"""Representation of an Acmeda cover sensor."""
|
||||||
|
|
||||||
_attr_device_class = SensorDeviceClass.BATTERY
|
_attr_device_class = SensorDeviceClass.BATTERY
|
||||||
|
|
|
@ -9,7 +9,7 @@ from typing import Final
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.device_tracker import (
|
from homeassistant.components.device_tracker import (
|
||||||
DOMAIN,
|
DOMAIN as DEVICE_TRACKER_DOMAIN,
|
||||||
PLATFORM_SCHEMA as DEVICE_TRACKER_PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA as DEVICE_TRACKER_PLATFORM_SCHEMA,
|
||||||
DeviceScanner,
|
DeviceScanner,
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ def get_scanner(
|
||||||
hass: HomeAssistant, config: ConfigType
|
hass: HomeAssistant, config: ConfigType
|
||||||
) -> ActiontecDeviceScanner | None:
|
) -> ActiontecDeviceScanner | None:
|
||||||
"""Validate the configuration and return an Actiontec scanner."""
|
"""Validate the configuration and return an Actiontec scanner."""
|
||||||
scanner = ActiontecDeviceScanner(config[DOMAIN])
|
scanner = ActiontecDeviceScanner(config[DEVICE_TRACKER_DOMAIN])
|
||||||
return scanner if scanner.success_init else None
|
return scanner if scanner.success_init else None
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ class ActiontecDeviceScanner(DeviceScanner):
|
||||||
self.last_results: list[Device] = []
|
self.last_results: list[Device] = []
|
||||||
data = self.get_actiontec_data()
|
data = self.get_actiontec_data()
|
||||||
self.success_init = data is not None
|
self.success_init = data is not None
|
||||||
_LOGGER.info("Scanner initialized")
|
|
||||||
|
|
||||||
def scan_devices(self) -> list[str]:
|
def scan_devices(self) -> list[str]:
|
||||||
"""Scan for new devices and return a list with found device IDs."""
|
"""Scan for new devices and return a list with found device IDs."""
|
||||||
|
@ -70,7 +69,7 @@ class ActiontecDeviceScanner(DeviceScanner):
|
||||||
|
|
||||||
Return boolean if scanning successful.
|
Return boolean if scanning successful.
|
||||||
"""
|
"""
|
||||||
_LOGGER.info("Scanning")
|
_LOGGER.debug("Scanning")
|
||||||
if not self.success_init:
|
if not self.success_init:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -79,7 +78,7 @@ class ActiontecDeviceScanner(DeviceScanner):
|
||||||
self.last_results = [
|
self.last_results = [
|
||||||
device for device in actiontec_data if device.timevalid > -60
|
device for device in actiontec_data if device.timevalid > -60
|
||||||
]
|
]
|
||||||
_LOGGER.info("Scan successful")
|
_LOGGER.debug("Scan successful")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_actiontec_data(self) -> list[Device] | None:
|
def get_actiontec_data(self) -> list[Device] | None:
|
||||||
|
|
|
@ -130,7 +130,7 @@ class AdaxConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
async_get_clientsession(self.hass), account_id, password
|
async_get_clientsession(self.hass), account_id, password
|
||||||
)
|
)
|
||||||
if token is None:
|
if token is None:
|
||||||
_LOGGER.info("Adax: Failed to login to retrieve token")
|
_LOGGER.debug("Adax: Failed to login to retrieve token")
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="cloud",
|
step_id="cloud",
|
||||||
|
|
|
@ -7,7 +7,6 @@ from typing import Any
|
||||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
|
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.hassio import HassioServiceInfo
|
|
||||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
|
@ -18,6 +17,7 @@ from homeassistant.const import (
|
||||||
CONF_VERIFY_SSL,
|
CONF_VERIFY_SSL,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.service_info.hassio import HassioServiceInfo
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"add_url": "mdi:link-plus",
|
"add_url": {
|
||||||
"remove_url": "mdi:link-off",
|
"service": "mdi:link-plus"
|
||||||
"enable_url": "mdi:link-variant",
|
},
|
||||||
"disable_url": "mdi:link-variant-off",
|
"remove_url": {
|
||||||
"refresh": "mdi:refresh"
|
"service": "mdi:link-off"
|
||||||
|
},
|
||||||
|
"enable_url": {
|
||||||
|
"service": "mdi:link-variant"
|
||||||
|
},
|
||||||
|
"disable_url": {
|
||||||
|
"service": "mdi:link-variant-off"
|
||||||
|
},
|
||||||
|
"refresh": {
|
||||||
|
"service": "mdi:refresh"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
"""Support for Automation Device Specification (ADS)."""
|
"""Support for Automation Device Specification (ADS)."""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from asyncio import timeout
|
|
||||||
from collections import namedtuple
|
|
||||||
import ctypes
|
|
||||||
import logging
|
import logging
|
||||||
import struct
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import pyads
|
import pyads
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
@ -19,42 +13,38 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
|
from .const import CONF_ADS_VAR, DATA_ADS, DOMAIN, AdsType
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DATA_ADS = "data_ads"
|
|
||||||
|
|
||||||
# Supported Types
|
|
||||||
ADSTYPE_BOOL = "bool"
|
|
||||||
ADSTYPE_BYTE = "byte"
|
|
||||||
ADSTYPE_DINT = "dint"
|
|
||||||
ADSTYPE_INT = "int"
|
|
||||||
ADSTYPE_UDINT = "udint"
|
|
||||||
ADSTYPE_UINT = "uint"
|
|
||||||
|
|
||||||
ADS_TYPEMAP = {
|
ADS_TYPEMAP = {
|
||||||
ADSTYPE_BOOL: pyads.PLCTYPE_BOOL,
|
AdsType.BOOL: pyads.PLCTYPE_BOOL,
|
||||||
ADSTYPE_BYTE: pyads.PLCTYPE_BYTE,
|
AdsType.BYTE: pyads.PLCTYPE_BYTE,
|
||||||
ADSTYPE_DINT: pyads.PLCTYPE_DINT,
|
AdsType.INT: pyads.PLCTYPE_INT,
|
||||||
ADSTYPE_INT: pyads.PLCTYPE_INT,
|
AdsType.UINT: pyads.PLCTYPE_UINT,
|
||||||
ADSTYPE_UDINT: pyads.PLCTYPE_UDINT,
|
AdsType.SINT: pyads.PLCTYPE_SINT,
|
||||||
ADSTYPE_UINT: pyads.PLCTYPE_UINT,
|
AdsType.USINT: pyads.PLCTYPE_USINT,
|
||||||
|
AdsType.DINT: pyads.PLCTYPE_DINT,
|
||||||
|
AdsType.UDINT: pyads.PLCTYPE_UDINT,
|
||||||
|
AdsType.WORD: pyads.PLCTYPE_WORD,
|
||||||
|
AdsType.DWORD: pyads.PLCTYPE_DWORD,
|
||||||
|
AdsType.REAL: pyads.PLCTYPE_REAL,
|
||||||
|
AdsType.LREAL: pyads.PLCTYPE_LREAL,
|
||||||
|
AdsType.STRING: pyads.PLCTYPE_STRING,
|
||||||
|
AdsType.TIME: pyads.PLCTYPE_TIME,
|
||||||
|
AdsType.DATE: pyads.PLCTYPE_DATE,
|
||||||
|
AdsType.DATE_AND_TIME: pyads.PLCTYPE_DT,
|
||||||
|
AdsType.TOD: pyads.PLCTYPE_TOD,
|
||||||
}
|
}
|
||||||
|
|
||||||
CONF_ADS_FACTOR = "factor"
|
CONF_ADS_FACTOR = "factor"
|
||||||
CONF_ADS_TYPE = "adstype"
|
CONF_ADS_TYPE = "adstype"
|
||||||
CONF_ADS_VALUE = "value"
|
CONF_ADS_VALUE = "value"
|
||||||
CONF_ADS_VAR = "adsvar"
|
|
||||||
CONF_ADS_VAR_BRIGHTNESS = "adsvar_brightness"
|
|
||||||
CONF_ADS_VAR_POSITION = "adsvar_position"
|
|
||||||
|
|
||||||
STATE_KEY_STATE = "state"
|
|
||||||
STATE_KEY_BRIGHTNESS = "brightness"
|
|
||||||
STATE_KEY_POSITION = "position"
|
|
||||||
|
|
||||||
DOMAIN = "ads"
|
|
||||||
|
|
||||||
SERVICE_WRITE_DATA_BY_NAME = "write_data_by_name"
|
SERVICE_WRITE_DATA_BY_NAME = "write_data_by_name"
|
||||||
|
|
||||||
|
@ -73,16 +63,7 @@ CONFIG_SCHEMA = vol.Schema(
|
||||||
|
|
||||||
SCHEMA_SERVICE_WRITE_DATA_BY_NAME = vol.Schema(
|
SCHEMA_SERVICE_WRITE_DATA_BY_NAME = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_ADS_TYPE): vol.In(
|
vol.Required(CONF_ADS_TYPE): vol.Coerce(AdsType),
|
||||||
[
|
|
||||||
ADSTYPE_INT,
|
|
||||||
ADSTYPE_UINT,
|
|
||||||
ADSTYPE_BYTE,
|
|
||||||
ADSTYPE_BOOL,
|
|
||||||
ADSTYPE_DINT,
|
|
||||||
ADSTYPE_UDINT,
|
|
||||||
]
|
|
||||||
),
|
|
||||||
vol.Required(CONF_ADS_VALUE): vol.Coerce(int),
|
vol.Required(CONF_ADS_VALUE): vol.Coerce(int),
|
||||||
vol.Required(CONF_ADS_VAR): cv.string,
|
vol.Required(CONF_ADS_VAR): cv.string,
|
||||||
}
|
}
|
||||||
|
@ -116,9 +97,9 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
||||||
def handle_write_data_by_name(call: ServiceCall) -> None:
|
def handle_write_data_by_name(call: ServiceCall) -> None:
|
||||||
"""Write a value to the connected ADS device."""
|
"""Write a value to the connected ADS device."""
|
||||||
ads_var = call.data[CONF_ADS_VAR]
|
ads_var: str = call.data[CONF_ADS_VAR]
|
||||||
ads_type = call.data[CONF_ADS_TYPE]
|
ads_type: AdsType = call.data[CONF_ADS_TYPE]
|
||||||
value = call.data[CONF_ADS_VALUE]
|
value: int = call.data[CONF_ADS_VALUE]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ads.write_by_name(ads_var, value, ADS_TYPEMAP[ads_type])
|
ads.write_by_name(ads_var, value, ADS_TYPEMAP[ads_type])
|
||||||
|
@ -133,181 +114,3 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# Tuple to hold data needed for notification
|
|
||||||
NotificationItem = namedtuple(
|
|
||||||
"NotificationItem", "hnotify huser name plc_datatype callback"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AdsHub:
|
|
||||||
"""Representation of an ADS connection."""
|
|
||||||
|
|
||||||
def __init__(self, ads_client):
|
|
||||||
"""Initialize the ADS hub."""
|
|
||||||
self._client = ads_client
|
|
||||||
self._client.open()
|
|
||||||
|
|
||||||
# All ADS devices are registered here
|
|
||||||
self._devices = []
|
|
||||||
self._notification_items = {}
|
|
||||||
self._lock = threading.Lock()
|
|
||||||
|
|
||||||
def shutdown(self, *args, **kwargs):
|
|
||||||
"""Shutdown ADS connection."""
|
|
||||||
|
|
||||||
_LOGGER.debug("Shutting down ADS")
|
|
||||||
for notification_item in self._notification_items.values():
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Deleting device notification %d, %d",
|
|
||||||
notification_item.hnotify,
|
|
||||||
notification_item.huser,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
self._client.del_device_notification(
|
|
||||||
notification_item.hnotify, notification_item.huser
|
|
||||||
)
|
|
||||||
except pyads.ADSError as err:
|
|
||||||
_LOGGER.error(err)
|
|
||||||
try:
|
|
||||||
self._client.close()
|
|
||||||
except pyads.ADSError as err:
|
|
||||||
_LOGGER.error(err)
|
|
||||||
|
|
||||||
def register_device(self, device):
|
|
||||||
"""Register a new device."""
|
|
||||||
self._devices.append(device)
|
|
||||||
|
|
||||||
def write_by_name(self, name, value, plc_datatype):
|
|
||||||
"""Write a value to the device."""
|
|
||||||
|
|
||||||
with self._lock:
|
|
||||||
try:
|
|
||||||
return self._client.write_by_name(name, value, plc_datatype)
|
|
||||||
except pyads.ADSError as err:
|
|
||||||
_LOGGER.error("Error writing %s: %s", name, err)
|
|
||||||
|
|
||||||
def read_by_name(self, name, plc_datatype):
|
|
||||||
"""Read a value from the device."""
|
|
||||||
|
|
||||||
with self._lock:
|
|
||||||
try:
|
|
||||||
return self._client.read_by_name(name, plc_datatype)
|
|
||||||
except pyads.ADSError as err:
|
|
||||||
_LOGGER.error("Error reading %s: %s", name, err)
|
|
||||||
|
|
||||||
def add_device_notification(self, name, plc_datatype, callback):
|
|
||||||
"""Add a notification to the ADS devices."""
|
|
||||||
|
|
||||||
attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype))
|
|
||||||
|
|
||||||
with self._lock:
|
|
||||||
try:
|
|
||||||
hnotify, huser = self._client.add_device_notification(
|
|
||||||
name, attr, self._device_notification_callback
|
|
||||||
)
|
|
||||||
except pyads.ADSError as err:
|
|
||||||
_LOGGER.error("Error subscribing to %s: %s", name, err)
|
|
||||||
else:
|
|
||||||
hnotify = int(hnotify)
|
|
||||||
self._notification_items[hnotify] = NotificationItem(
|
|
||||||
hnotify, huser, name, plc_datatype, callback
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Added device notification %d for variable %s", hnotify, name
|
|
||||||
)
|
|
||||||
|
|
||||||
def _device_notification_callback(self, notification, name):
|
|
||||||
"""Handle device notifications."""
|
|
||||||
contents = notification.contents
|
|
||||||
|
|
||||||
hnotify = int(contents.hNotification)
|
|
||||||
_LOGGER.debug("Received notification %d", hnotify)
|
|
||||||
|
|
||||||
# get dynamically sized data array
|
|
||||||
data_size = contents.cbSampleSize
|
|
||||||
data = (ctypes.c_ubyte * data_size).from_address(
|
|
||||||
ctypes.addressof(contents)
|
|
||||||
+ pyads.structs.SAdsNotificationHeader.data.offset
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with self._lock:
|
|
||||||
notification_item = self._notification_items[hnotify]
|
|
||||||
except KeyError:
|
|
||||||
_LOGGER.error("Unknown device notification handle: %d", hnotify)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Parse data to desired datatype
|
|
||||||
if notification_item.plc_datatype == pyads.PLCTYPE_BOOL:
|
|
||||||
value = bool(struct.unpack("<?", bytearray(data))[0])
|
|
||||||
elif notification_item.plc_datatype == pyads.PLCTYPE_INT:
|
|
||||||
value = struct.unpack("<h", bytearray(data))[0]
|
|
||||||
elif notification_item.plc_datatype == pyads.PLCTYPE_BYTE:
|
|
||||||
value = struct.unpack("<B", bytearray(data))[0]
|
|
||||||
elif notification_item.plc_datatype == pyads.PLCTYPE_UINT:
|
|
||||||
value = struct.unpack("<H", bytearray(data))[0]
|
|
||||||
elif notification_item.plc_datatype == pyads.PLCTYPE_DINT:
|
|
||||||
value = struct.unpack("<i", bytearray(data))[0]
|
|
||||||
elif notification_item.plc_datatype == pyads.PLCTYPE_UDINT:
|
|
||||||
value = struct.unpack("<I", bytearray(data))[0]
|
|
||||||
else:
|
|
||||||
value = bytearray(data)
|
|
||||||
_LOGGER.warning("No callback available for this datatype")
|
|
||||||
|
|
||||||
notification_item.callback(notification_item.name, value)
|
|
||||||
|
|
||||||
|
|
||||||
class AdsEntity(Entity):
|
|
||||||
"""Representation of ADS entity."""
|
|
||||||
|
|
||||||
_attr_should_poll = False
|
|
||||||
|
|
||||||
def __init__(self, ads_hub, name, ads_var):
|
|
||||||
"""Initialize ADS binary sensor."""
|
|
||||||
self._state_dict = {}
|
|
||||||
self._state_dict[STATE_KEY_STATE] = None
|
|
||||||
self._ads_hub = ads_hub
|
|
||||||
self._ads_var = ads_var
|
|
||||||
self._event = None
|
|
||||||
self._attr_unique_id = ads_var
|
|
||||||
self._attr_name = name
|
|
||||||
|
|
||||||
async def async_initialize_device(
|
|
||||||
self, ads_var, plctype, state_key=STATE_KEY_STATE, factor=None
|
|
||||||
):
|
|
||||||
"""Register device notification."""
|
|
||||||
|
|
||||||
def update(name, value):
|
|
||||||
"""Handle device notifications."""
|
|
||||||
_LOGGER.debug("Variable %s changed its value to %d", name, value)
|
|
||||||
|
|
||||||
if factor is None:
|
|
||||||
self._state_dict[state_key] = value
|
|
||||||
else:
|
|
||||||
self._state_dict[state_key] = value / factor
|
|
||||||
|
|
||||||
asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop)
|
|
||||||
self.schedule_update_ha_state()
|
|
||||||
|
|
||||||
async def async_event_set():
|
|
||||||
"""Set event in async context."""
|
|
||||||
self._event.set()
|
|
||||||
|
|
||||||
self._event = asyncio.Event()
|
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(
|
|
||||||
self._ads_hub.add_device_notification, ads_var, plctype, update
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
async with timeout(10):
|
|
||||||
await self._event.wait()
|
|
||||||
except TimeoutError:
|
|
||||||
_LOGGER.debug("Variable %s: Timeout during first update", ads_var)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self) -> bool:
|
|
||||||
"""Return False if state has not been updated yet."""
|
|
||||||
return self._state_dict[STATE_KEY_STATE] is not None
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE, AdsEntity
|
from .const import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE
|
||||||
|
from .entity import AdsEntity
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
DEFAULT_NAME = "ADS binary sensor"
|
DEFAULT_NAME = "ADS binary sensor"
|
||||||
PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
|
||||||
|
@ -36,11 +38,11 @@ def setup_platform(
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Binary Sensor platform for ADS."""
|
"""Set up the Binary Sensor platform for ADS."""
|
||||||
ads_hub = hass.data.get(DATA_ADS)
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
ads_var = config[CONF_ADS_VAR]
|
ads_var: str = config[CONF_ADS_VAR]
|
||||||
name = config[CONF_NAME]
|
name: str = config[CONF_NAME]
|
||||||
device_class = config.get(CONF_DEVICE_CLASS)
|
device_class: BinarySensorDeviceClass | None = config.get(CONF_DEVICE_CLASS)
|
||||||
|
|
||||||
ads_sensor = AdsBinarySensor(ads_hub, name, ads_var, device_class)
|
ads_sensor = AdsBinarySensor(ads_hub, name, ads_var, device_class)
|
||||||
add_entities([ads_sensor])
|
add_entities([ads_sensor])
|
||||||
|
@ -49,7 +51,13 @@ def setup_platform(
|
||||||
class AdsBinarySensor(AdsEntity, BinarySensorEntity):
|
class AdsBinarySensor(AdsEntity, BinarySensorEntity):
|
||||||
"""Representation of ADS binary sensors."""
|
"""Representation of ADS binary sensors."""
|
||||||
|
|
||||||
def __init__(self, ads_hub, name, ads_var, device_class):
|
def __init__(
|
||||||
|
self,
|
||||||
|
ads_hub: AdsHub,
|
||||||
|
name: str,
|
||||||
|
ads_var: str,
|
||||||
|
device_class: BinarySensorDeviceClass | None,
|
||||||
|
) -> None:
|
||||||
"""Initialize ADS binary sensor."""
|
"""Initialize ADS binary sensor."""
|
||||||
super().__init__(ads_hub, name, ads_var)
|
super().__init__(ads_hub, name, ads_var)
|
||||||
self._attr_device_class = device_class or BinarySensorDeviceClass.MOVING
|
self._attr_device_class = device_class or BinarySensorDeviceClass.MOVING
|
||||||
|
|
41
homeassistant/components/ads/const.py
Normal file
41
homeassistant/components/ads/const.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"""Support for Automation Device Specification (ADS)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from enum import StrEnum
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from homeassistant.util.hass_dict import HassKey
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
|
DOMAIN = "ads"
|
||||||
|
|
||||||
|
DATA_ADS: HassKey[AdsHub] = HassKey(DOMAIN)
|
||||||
|
|
||||||
|
CONF_ADS_VAR = "adsvar"
|
||||||
|
|
||||||
|
STATE_KEY_STATE = "state"
|
||||||
|
|
||||||
|
|
||||||
|
class AdsType(StrEnum):
|
||||||
|
"""Supported Types."""
|
||||||
|
|
||||||
|
BOOL = "bool"
|
||||||
|
BYTE = "byte"
|
||||||
|
INT = "int"
|
||||||
|
UINT = "uint"
|
||||||
|
SINT = "sint"
|
||||||
|
USINT = "usint"
|
||||||
|
DINT = "dint"
|
||||||
|
UDINT = "udint"
|
||||||
|
WORD = "word"
|
||||||
|
DWORD = "dword"
|
||||||
|
LREAL = "lreal"
|
||||||
|
REAL = "real"
|
||||||
|
STRING = "string"
|
||||||
|
TIME = "time"
|
||||||
|
DATE = "date"
|
||||||
|
DATE_AND_TIME = "dt"
|
||||||
|
TOD = "tod"
|
|
@ -11,6 +11,7 @@ from homeassistant.components.cover import (
|
||||||
ATTR_POSITION,
|
ATTR_POSITION,
|
||||||
DEVICE_CLASSES_SCHEMA,
|
DEVICE_CLASSES_SCHEMA,
|
||||||
PLATFORM_SCHEMA as COVER_PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA as COVER_PLATFORM_SCHEMA,
|
||||||
|
CoverDeviceClass,
|
||||||
CoverEntity,
|
CoverEntity,
|
||||||
CoverEntityFeature,
|
CoverEntityFeature,
|
||||||
)
|
)
|
||||||
|
@ -20,14 +21,9 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import (
|
from .const import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE
|
||||||
CONF_ADS_VAR,
|
from .entity import AdsEntity
|
||||||
CONF_ADS_VAR_POSITION,
|
from .hub import AdsHub
|
||||||
DATA_ADS,
|
|
||||||
STATE_KEY_POSITION,
|
|
||||||
STATE_KEY_STATE,
|
|
||||||
AdsEntity,
|
|
||||||
)
|
|
||||||
|
|
||||||
DEFAULT_NAME = "ADS Cover"
|
DEFAULT_NAME = "ADS Cover"
|
||||||
|
|
||||||
|
@ -35,6 +31,9 @@ CONF_ADS_VAR_SET_POS = "adsvar_set_position"
|
||||||
CONF_ADS_VAR_OPEN = "adsvar_open"
|
CONF_ADS_VAR_OPEN = "adsvar_open"
|
||||||
CONF_ADS_VAR_CLOSE = "adsvar_close"
|
CONF_ADS_VAR_CLOSE = "adsvar_close"
|
||||||
CONF_ADS_VAR_STOP = "adsvar_stop"
|
CONF_ADS_VAR_STOP = "adsvar_stop"
|
||||||
|
CONF_ADS_VAR_POSITION = "adsvar_position"
|
||||||
|
|
||||||
|
STATE_KEY_POSITION = "position"
|
||||||
|
|
||||||
PLATFORM_SCHEMA = COVER_PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = COVER_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
|
@ -59,14 +58,14 @@ def setup_platform(
|
||||||
"""Set up the cover platform for ADS."""
|
"""Set up the cover platform for ADS."""
|
||||||
ads_hub = hass.data[DATA_ADS]
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
ads_var_is_closed = config.get(CONF_ADS_VAR)
|
ads_var_is_closed: str = config[CONF_ADS_VAR]
|
||||||
ads_var_position = config.get(CONF_ADS_VAR_POSITION)
|
ads_var_position: str | None = config.get(CONF_ADS_VAR_POSITION)
|
||||||
ads_var_pos_set = config.get(CONF_ADS_VAR_SET_POS)
|
ads_var_pos_set: str | None = config.get(CONF_ADS_VAR_SET_POS)
|
||||||
ads_var_open = config.get(CONF_ADS_VAR_OPEN)
|
ads_var_open: str | None = config.get(CONF_ADS_VAR_OPEN)
|
||||||
ads_var_close = config.get(CONF_ADS_VAR_CLOSE)
|
ads_var_close: str | None = config.get(CONF_ADS_VAR_CLOSE)
|
||||||
ads_var_stop = config.get(CONF_ADS_VAR_STOP)
|
ads_var_stop: str | None = config.get(CONF_ADS_VAR_STOP)
|
||||||
name = config[CONF_NAME]
|
name: str = config[CONF_NAME]
|
||||||
device_class = config.get(CONF_DEVICE_CLASS)
|
device_class: CoverDeviceClass | None = config.get(CONF_DEVICE_CLASS)
|
||||||
|
|
||||||
add_entities(
|
add_entities(
|
||||||
[
|
[
|
||||||
|
@ -90,16 +89,16 @@ class AdsCover(AdsEntity, CoverEntity):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
ads_hub,
|
ads_hub: AdsHub,
|
||||||
ads_var_is_closed,
|
ads_var_is_closed: str,
|
||||||
ads_var_position,
|
ads_var_position: str | None,
|
||||||
ads_var_pos_set,
|
ads_var_pos_set: str | None,
|
||||||
ads_var_open,
|
ads_var_open: str | None,
|
||||||
ads_var_close,
|
ads_var_close: str | None,
|
||||||
ads_var_stop,
|
ads_var_stop: str | None,
|
||||||
name,
|
name: str,
|
||||||
device_class,
|
device_class: CoverDeviceClass | None,
|
||||||
):
|
) -> None:
|
||||||
"""Initialize AdsCover entity."""
|
"""Initialize AdsCover entity."""
|
||||||
super().__init__(ads_hub, name, ads_var_is_closed)
|
super().__init__(ads_hub, name, ads_var_is_closed)
|
||||||
if self._attr_unique_id is None:
|
if self._attr_unique_id is None:
|
||||||
|
|
70
homeassistant/components/ads/entity.py
Normal file
70
homeassistant/components/ads/entity.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
"""Support for Automation Device Specification (ADS)."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from asyncio import timeout
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .const import STATE_KEY_STATE
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AdsEntity(Entity):
|
||||||
|
"""Representation of ADS entity."""
|
||||||
|
|
||||||
|
_attr_should_poll = False
|
||||||
|
|
||||||
|
def __init__(self, ads_hub: AdsHub, name: str, ads_var: str) -> None:
|
||||||
|
"""Initialize ADS binary sensor."""
|
||||||
|
self._state_dict: dict[str, Any] = {}
|
||||||
|
self._state_dict[STATE_KEY_STATE] = None
|
||||||
|
self._ads_hub = ads_hub
|
||||||
|
self._ads_var = ads_var
|
||||||
|
self._event: asyncio.Event | None = None
|
||||||
|
self._attr_unique_id = ads_var
|
||||||
|
self._attr_name = name
|
||||||
|
|
||||||
|
async def async_initialize_device(
|
||||||
|
self,
|
||||||
|
ads_var: str,
|
||||||
|
plctype: type,
|
||||||
|
state_key: str = STATE_KEY_STATE,
|
||||||
|
factor: int | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Register device notification."""
|
||||||
|
|
||||||
|
def update(name, value):
|
||||||
|
"""Handle device notifications."""
|
||||||
|
_LOGGER.debug("Variable %s changed its value to %d", name, value)
|
||||||
|
|
||||||
|
if factor is None:
|
||||||
|
self._state_dict[state_key] = value
|
||||||
|
else:
|
||||||
|
self._state_dict[state_key] = value / factor
|
||||||
|
|
||||||
|
asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop)
|
||||||
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
async def async_event_set():
|
||||||
|
"""Set event in async context."""
|
||||||
|
self._event.set()
|
||||||
|
|
||||||
|
self._event = asyncio.Event()
|
||||||
|
|
||||||
|
await self.hass.async_add_executor_job(
|
||||||
|
self._ads_hub.add_device_notification, ads_var, plctype, update
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
async with timeout(10):
|
||||||
|
await self._event.wait()
|
||||||
|
except TimeoutError:
|
||||||
|
_LOGGER.debug("Variable %s: Timeout during first update", ads_var)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Return False if state has not been updated yet."""
|
||||||
|
return self._state_dict[STATE_KEY_STATE] is not None
|
151
homeassistant/components/ads/hub.py
Normal file
151
homeassistant/components/ads/hub.py
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
"""Support for Automation Device Specification (ADS)."""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
import ctypes
|
||||||
|
import logging
|
||||||
|
import struct
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import pyads
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Tuple to hold data needed for notification
|
||||||
|
NotificationItem = namedtuple( # noqa: PYI024
|
||||||
|
"NotificationItem", "hnotify huser name plc_datatype callback"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AdsHub:
|
||||||
|
"""Representation of an ADS connection."""
|
||||||
|
|
||||||
|
def __init__(self, ads_client):
|
||||||
|
"""Initialize the ADS hub."""
|
||||||
|
self._client = ads_client
|
||||||
|
self._client.open()
|
||||||
|
|
||||||
|
# All ADS devices are registered here
|
||||||
|
self._devices = []
|
||||||
|
self._notification_items = {}
|
||||||
|
self._lock = threading.Lock()
|
||||||
|
|
||||||
|
def shutdown(self, *args, **kwargs):
|
||||||
|
"""Shutdown ADS connection."""
|
||||||
|
|
||||||
|
_LOGGER.debug("Shutting down ADS")
|
||||||
|
for notification_item in self._notification_items.values():
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Deleting device notification %d, %d",
|
||||||
|
notification_item.hnotify,
|
||||||
|
notification_item.huser,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
self._client.del_device_notification(
|
||||||
|
notification_item.hnotify, notification_item.huser
|
||||||
|
)
|
||||||
|
except pyads.ADSError as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
|
try:
|
||||||
|
self._client.close()
|
||||||
|
except pyads.ADSError as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
|
|
||||||
|
def register_device(self, device):
|
||||||
|
"""Register a new device."""
|
||||||
|
self._devices.append(device)
|
||||||
|
|
||||||
|
def write_by_name(self, name, value, plc_datatype):
|
||||||
|
"""Write a value to the device."""
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
try:
|
||||||
|
return self._client.write_by_name(name, value, plc_datatype)
|
||||||
|
except pyads.ADSError as err:
|
||||||
|
_LOGGER.error("Error writing %s: %s", name, err)
|
||||||
|
|
||||||
|
def read_by_name(self, name, plc_datatype):
|
||||||
|
"""Read a value from the device."""
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
try:
|
||||||
|
return self._client.read_by_name(name, plc_datatype)
|
||||||
|
except pyads.ADSError as err:
|
||||||
|
_LOGGER.error("Error reading %s: %s", name, err)
|
||||||
|
|
||||||
|
def add_device_notification(self, name, plc_datatype, callback):
|
||||||
|
"""Add a notification to the ADS devices."""
|
||||||
|
|
||||||
|
attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype))
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
try:
|
||||||
|
hnotify, huser = self._client.add_device_notification(
|
||||||
|
name, attr, self._device_notification_callback
|
||||||
|
)
|
||||||
|
except pyads.ADSError as err:
|
||||||
|
_LOGGER.error("Error subscribing to %s: %s", name, err)
|
||||||
|
else:
|
||||||
|
hnotify = int(hnotify)
|
||||||
|
self._notification_items[hnotify] = NotificationItem(
|
||||||
|
hnotify, huser, name, plc_datatype, callback
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Added device notification %d for variable %s", hnotify, name
|
||||||
|
)
|
||||||
|
|
||||||
|
def _device_notification_callback(self, notification, name):
|
||||||
|
"""Handle device notifications."""
|
||||||
|
contents = notification.contents
|
||||||
|
hnotify = int(contents.hNotification)
|
||||||
|
_LOGGER.debug("Received notification %d", hnotify)
|
||||||
|
|
||||||
|
# Get dynamically sized data array
|
||||||
|
data_size = contents.cbSampleSize
|
||||||
|
data_address = (
|
||||||
|
ctypes.addressof(contents)
|
||||||
|
+ pyads.structs.SAdsNotificationHeader.data.offset
|
||||||
|
)
|
||||||
|
data = (ctypes.c_ubyte * data_size).from_address(data_address)
|
||||||
|
|
||||||
|
# Acquire notification item
|
||||||
|
with self._lock:
|
||||||
|
notification_item = self._notification_items.get(hnotify)
|
||||||
|
|
||||||
|
if not notification_item:
|
||||||
|
_LOGGER.error("Unknown device notification handle: %d", hnotify)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Data parsing based on PLC data type
|
||||||
|
plc_datatype = notification_item.plc_datatype
|
||||||
|
unpack_formats = {
|
||||||
|
pyads.PLCTYPE_BYTE: "<b",
|
||||||
|
pyads.PLCTYPE_INT: "<h",
|
||||||
|
pyads.PLCTYPE_UINT: "<H",
|
||||||
|
pyads.PLCTYPE_SINT: "<b",
|
||||||
|
pyads.PLCTYPE_USINT: "<B",
|
||||||
|
pyads.PLCTYPE_DINT: "<i",
|
||||||
|
pyads.PLCTYPE_UDINT: "<I",
|
||||||
|
pyads.PLCTYPE_WORD: "<H",
|
||||||
|
pyads.PLCTYPE_DWORD: "<I",
|
||||||
|
pyads.PLCTYPE_LREAL: "<d",
|
||||||
|
pyads.PLCTYPE_REAL: "<f",
|
||||||
|
pyads.PLCTYPE_TOD: "<i", # Treat as DINT
|
||||||
|
pyads.PLCTYPE_DATE: "<i", # Treat as DINT
|
||||||
|
pyads.PLCTYPE_DT: "<i", # Treat as DINT
|
||||||
|
pyads.PLCTYPE_TIME: "<i", # Treat as DINT
|
||||||
|
}
|
||||||
|
|
||||||
|
if plc_datatype == pyads.PLCTYPE_BOOL:
|
||||||
|
value = bool(struct.unpack("<?", bytearray(data))[0])
|
||||||
|
elif plc_datatype == pyads.PLCTYPE_STRING:
|
||||||
|
value = (
|
||||||
|
bytearray(data).split(b"\x00", 1)[0].decode("utf-8", errors="ignore")
|
||||||
|
)
|
||||||
|
elif plc_datatype in unpack_formats:
|
||||||
|
value = struct.unpack(unpack_formats[plc_datatype], bytearray(data))[0]
|
||||||
|
else:
|
||||||
|
value = bytearray(data)
|
||||||
|
_LOGGER.warning("No callback available for this datatype")
|
||||||
|
|
||||||
|
notification_item.callback(notification_item.name, value)
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"services": {
|
"services": {
|
||||||
"write_data_by_name": "mdi:pencil"
|
"write_data_by_name": {
|
||||||
|
"service": "mdi:pencil"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,12 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import (
|
from .const import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE
|
||||||
CONF_ADS_VAR,
|
from .entity import AdsEntity
|
||||||
CONF_ADS_VAR_BRIGHTNESS,
|
from .hub import AdsHub
|
||||||
DATA_ADS,
|
|
||||||
STATE_KEY_BRIGHTNESS,
|
CONF_ADS_VAR_BRIGHTNESS = "adsvar_brightness"
|
||||||
STATE_KEY_STATE,
|
STATE_KEY_BRIGHTNESS = "brightness"
|
||||||
AdsEntity,
|
|
||||||
)
|
|
||||||
|
|
||||||
DEFAULT_NAME = "ADS Light"
|
DEFAULT_NAME = "ADS Light"
|
||||||
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
|
||||||
|
@ -45,11 +43,11 @@ def setup_platform(
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the light platform for ADS."""
|
"""Set up the light platform for ADS."""
|
||||||
ads_hub = hass.data.get(DATA_ADS)
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
ads_var_enable = config[CONF_ADS_VAR]
|
ads_var_enable: str = config[CONF_ADS_VAR]
|
||||||
ads_var_brightness = config.get(CONF_ADS_VAR_BRIGHTNESS)
|
ads_var_brightness: str | None = config.get(CONF_ADS_VAR_BRIGHTNESS)
|
||||||
name = config[CONF_NAME]
|
name: str = config[CONF_NAME]
|
||||||
|
|
||||||
add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, name)])
|
add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, name)])
|
||||||
|
|
||||||
|
@ -57,7 +55,13 @@ def setup_platform(
|
||||||
class AdsLight(AdsEntity, LightEntity):
|
class AdsLight(AdsEntity, LightEntity):
|
||||||
"""Representation of ADS light."""
|
"""Representation of ADS light."""
|
||||||
|
|
||||||
def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name):
|
def __init__(
|
||||||
|
self,
|
||||||
|
ads_hub: AdsHub,
|
||||||
|
ads_var_enable: str,
|
||||||
|
ads_var_brightness: str | None,
|
||||||
|
name: str,
|
||||||
|
) -> None:
|
||||||
"""Initialize AdsLight entity."""
|
"""Initialize AdsLight entity."""
|
||||||
super().__init__(ads_hub, name, ads_var_enable)
|
super().__init__(ads_hub, name, ads_var_enable)
|
||||||
self._state_dict[STATE_KEY_BRIGHTNESS] = None
|
self._state_dict[STATE_KEY_BRIGHTNESS] = None
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"domain": "ads",
|
"domain": "ads",
|
||||||
"name": "ADS",
|
"name": "ADS",
|
||||||
"codeowners": [],
|
"codeowners": ["@mrpasztoradam"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ads",
|
"documentation": "https://www.home-assistant.io/integrations/ads",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["pyads"],
|
"loggers": ["pyads"],
|
||||||
|
|
86
homeassistant/components/ads/select.py
Normal file
86
homeassistant/components/ads/select.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
"""Support for ADS select entities."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pyads
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.select import (
|
||||||
|
PLATFORM_SCHEMA as SELECT_PLATFORM_SCHEMA,
|
||||||
|
SelectEntity,
|
||||||
|
)
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
|
from .const import CONF_ADS_VAR, DATA_ADS
|
||||||
|
from .entity import AdsEntity
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
|
DEFAULT_NAME = "ADS select"
|
||||||
|
|
||||||
|
CONF_OPTIONS = "options"
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = SELECT_PLATFORM_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ADS_VAR): cv.string,
|
||||||
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
|
vol.Required(CONF_OPTIONS): vol.All(cv.ensure_list, [cv.string]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType,
|
||||||
|
add_entities: AddEntitiesCallback,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Set up an ADS select device."""
|
||||||
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
|
ads_var: str = config[CONF_ADS_VAR]
|
||||||
|
name: str = config[CONF_NAME]
|
||||||
|
options: list[str] = config[CONF_OPTIONS]
|
||||||
|
|
||||||
|
entity = AdsSelect(ads_hub, ads_var, name, options)
|
||||||
|
|
||||||
|
add_entities([entity])
|
||||||
|
|
||||||
|
|
||||||
|
class AdsSelect(AdsEntity, SelectEntity):
|
||||||
|
"""Representation of an ADS select entity."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
ads_hub: AdsHub,
|
||||||
|
ads_var: str,
|
||||||
|
name: str,
|
||||||
|
options: list[str],
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the AdsSelect entity."""
|
||||||
|
super().__init__(ads_hub, name, ads_var)
|
||||||
|
self._attr_options = options
|
||||||
|
self._attr_current_option = None
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Register device notification."""
|
||||||
|
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_INT)
|
||||||
|
self._ads_hub.add_device_notification(
|
||||||
|
self._ads_var, pyads.PLCTYPE_INT, self._handle_ads_value
|
||||||
|
)
|
||||||
|
|
||||||
|
def select_option(self, option: str) -> None:
|
||||||
|
"""Change the selected option."""
|
||||||
|
if option in self._attr_options:
|
||||||
|
index = self._attr_options.index(option)
|
||||||
|
self._ads_hub.write_by_name(self._ads_var, index, pyads.PLCTYPE_INT)
|
||||||
|
self._attr_current_option = option
|
||||||
|
|
||||||
|
def _handle_ads_value(self, name: str, value: int) -> None:
|
||||||
|
"""Handle the value update from ADS."""
|
||||||
|
if 0 <= value < len(self._attr_options):
|
||||||
|
self._attr_current_option = self._attr_options[value]
|
||||||
|
self.schedule_update_ha_state()
|
|
@ -5,41 +5,54 @@ from __future__ import annotations
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
|
CONF_STATE_CLASS,
|
||||||
|
DEVICE_CLASSES_SCHEMA as SENSOR_DEVICE_CLASSES_SCHEMA,
|
||||||
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
||||||
|
STATE_CLASSES_SCHEMA as SENSOR_STATE_CLASSES_SCHEMA,
|
||||||
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT
|
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME, CONF_UNIT_OF_MEASUREMENT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
|
||||||
|
|
||||||
from .. import ads
|
from . import ADS_TYPEMAP, CONF_ADS_FACTOR, CONF_ADS_TYPE
|
||||||
from . import (
|
from .const import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE, AdsType
|
||||||
ADS_TYPEMAP,
|
from .entity import AdsEntity
|
||||||
CONF_ADS_FACTOR,
|
from .hub import AdsHub
|
||||||
CONF_ADS_TYPE,
|
|
||||||
CONF_ADS_VAR,
|
|
||||||
STATE_KEY_STATE,
|
|
||||||
AdsEntity,
|
|
||||||
)
|
|
||||||
|
|
||||||
DEFAULT_NAME = "ADS sensor"
|
DEFAULT_NAME = "ADS sensor"
|
||||||
|
|
||||||
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_ADS_VAR): cv.string,
|
vol.Required(CONF_ADS_VAR): cv.string,
|
||||||
vol.Optional(CONF_ADS_FACTOR): cv.positive_int,
|
vol.Optional(CONF_ADS_FACTOR): cv.positive_int,
|
||||||
vol.Optional(CONF_ADS_TYPE, default=ads.ADSTYPE_INT): vol.In(
|
vol.Optional(CONF_ADS_TYPE, default=AdsType.INT): vol.All(
|
||||||
[
|
vol.Coerce(AdsType),
|
||||||
ads.ADSTYPE_INT,
|
vol.In(
|
||||||
ads.ADSTYPE_UINT,
|
[
|
||||||
ads.ADSTYPE_BYTE,
|
AdsType.BOOL,
|
||||||
ads.ADSTYPE_DINT,
|
AdsType.BYTE,
|
||||||
ads.ADSTYPE_UDINT,
|
AdsType.INT,
|
||||||
]
|
AdsType.UINT,
|
||||||
|
AdsType.SINT,
|
||||||
|
AdsType.USINT,
|
||||||
|
AdsType.DINT,
|
||||||
|
AdsType.UDINT,
|
||||||
|
AdsType.WORD,
|
||||||
|
AdsType.DWORD,
|
||||||
|
AdsType.LREAL,
|
||||||
|
AdsType.REAL,
|
||||||
|
]
|
||||||
|
),
|
||||||
),
|
),
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT, default=""): cv.string,
|
vol.Optional(CONF_DEVICE_CLASS): SENSOR_DEVICE_CLASSES_SCHEMA,
|
||||||
|
vol.Optional(CONF_STATE_CLASS): SENSOR_STATE_CLASSES_SCHEMA,
|
||||||
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,15 +64,26 @@ def setup_platform(
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up an ADS sensor device."""
|
"""Set up an ADS sensor device."""
|
||||||
ads_hub = hass.data.get(ads.DATA_ADS)
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
ads_var = config[CONF_ADS_VAR]
|
ads_var: str = config[CONF_ADS_VAR]
|
||||||
ads_type = config[CONF_ADS_TYPE]
|
ads_type: AdsType = config[CONF_ADS_TYPE]
|
||||||
name = config[CONF_NAME]
|
name: str = config[CONF_NAME]
|
||||||
unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT)
|
factor: int | None = config.get(CONF_ADS_FACTOR)
|
||||||
factor = config.get(CONF_ADS_FACTOR)
|
device_class: SensorDeviceClass | None = config.get(CONF_DEVICE_CLASS)
|
||||||
|
state_class: SensorStateClass | None = config.get(CONF_STATE_CLASS)
|
||||||
|
unit_of_measurement: str | None = config.get(CONF_UNIT_OF_MEASUREMENT)
|
||||||
|
|
||||||
entity = AdsSensor(ads_hub, ads_var, ads_type, name, unit_of_measurement, factor)
|
entity = AdsSensor(
|
||||||
|
ads_hub,
|
||||||
|
ads_var,
|
||||||
|
ads_type,
|
||||||
|
name,
|
||||||
|
factor,
|
||||||
|
device_class,
|
||||||
|
state_class,
|
||||||
|
unit_of_measurement,
|
||||||
|
)
|
||||||
|
|
||||||
add_entities([entity])
|
add_entities([entity])
|
||||||
|
|
||||||
|
@ -67,12 +91,24 @@ def setup_platform(
|
||||||
class AdsSensor(AdsEntity, SensorEntity):
|
class AdsSensor(AdsEntity, SensorEntity):
|
||||||
"""Representation of an ADS sensor entity."""
|
"""Representation of an ADS sensor entity."""
|
||||||
|
|
||||||
def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement, factor):
|
def __init__(
|
||||||
|
self,
|
||||||
|
ads_hub: AdsHub,
|
||||||
|
ads_var: str,
|
||||||
|
ads_type: AdsType,
|
||||||
|
name: str,
|
||||||
|
factor: int | None,
|
||||||
|
device_class: SensorDeviceClass | None,
|
||||||
|
state_class: SensorStateClass | None,
|
||||||
|
unit_of_measurement: str | None,
|
||||||
|
) -> None:
|
||||||
"""Initialize AdsSensor entity."""
|
"""Initialize AdsSensor entity."""
|
||||||
super().__init__(ads_hub, name, ads_var)
|
super().__init__(ads_hub, name, ads_var)
|
||||||
self._attr_native_unit_of_measurement = unit_of_measurement
|
|
||||||
self._ads_type = ads_type
|
self._ads_type = ads_type
|
||||||
self._factor = factor
|
self._factor = factor
|
||||||
|
self._attr_device_class = device_class
|
||||||
|
self._attr_state_class = state_class
|
||||||
|
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Register device notification."""
|
"""Register device notification."""
|
||||||
|
|
|
@ -17,7 +17,8 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE, AdsEntity
|
from .const import CONF_ADS_VAR, DATA_ADS, STATE_KEY_STATE
|
||||||
|
from .entity import AdsEntity
|
||||||
|
|
||||||
DEFAULT_NAME = "ADS Switch"
|
DEFAULT_NAME = "ADS Switch"
|
||||||
|
|
||||||
|
@ -36,10 +37,10 @@ def setup_platform(
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up switch platform for ADS."""
|
"""Set up switch platform for ADS."""
|
||||||
ads_hub = hass.data.get(DATA_ADS)
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
name = config[CONF_NAME]
|
name: str = config[CONF_NAME]
|
||||||
ads_var = config[CONF_ADS_VAR]
|
ads_var: str = config[CONF_ADS_VAR]
|
||||||
|
|
||||||
add_entities([AdsSwitch(ads_hub, name, ads_var)])
|
add_entities([AdsSwitch(ads_hub, name, ads_var)])
|
||||||
|
|
||||||
|
|
84
homeassistant/components/ads/valve.py
Normal file
84
homeassistant/components/ads/valve.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
"""Support for ADS valves."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pyads
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.valve import (
|
||||||
|
DEVICE_CLASSES_SCHEMA as VALVE_DEVICE_CLASSES_SCHEMA,
|
||||||
|
PLATFORM_SCHEMA as VALVE_PLATFORM_SCHEMA,
|
||||||
|
ValveDeviceClass,
|
||||||
|
ValveEntity,
|
||||||
|
ValveEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
|
from .const import CONF_ADS_VAR, DATA_ADS
|
||||||
|
from .entity import AdsEntity
|
||||||
|
from .hub import AdsHub
|
||||||
|
|
||||||
|
DEFAULT_NAME = "ADS valve"
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = VALVE_PLATFORM_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ADS_VAR): cv.string,
|
||||||
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
|
vol.Optional(CONF_DEVICE_CLASS): VALVE_DEVICE_CLASSES_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType,
|
||||||
|
add_entities: AddEntitiesCallback,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Set up an ADS valve device."""
|
||||||
|
ads_hub = hass.data[DATA_ADS]
|
||||||
|
|
||||||
|
ads_var: str = config[CONF_ADS_VAR]
|
||||||
|
name: str = config[CONF_NAME]
|
||||||
|
device_class: ValveDeviceClass | None = config.get(CONF_DEVICE_CLASS)
|
||||||
|
|
||||||
|
entity = AdsValve(ads_hub, ads_var, name, device_class)
|
||||||
|
|
||||||
|
add_entities([entity])
|
||||||
|
|
||||||
|
|
||||||
|
class AdsValve(AdsEntity, ValveEntity):
|
||||||
|
"""Representation of an ADS valve entity."""
|
||||||
|
|
||||||
|
_attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
ads_hub: AdsHub,
|
||||||
|
ads_var: str,
|
||||||
|
name: str,
|
||||||
|
device_class: ValveDeviceClass | None,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize AdsValve entity."""
|
||||||
|
super().__init__(ads_hub, name, ads_var)
|
||||||
|
self._attr_device_class = device_class
|
||||||
|
self._attr_reports_position = False
|
||||||
|
self._attr_is_closed = True
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Register device notification."""
|
||||||
|
await self.async_initialize_device(self._ads_var, pyads.PLCTYPE_BOOL)
|
||||||
|
|
||||||
|
def open_valve(self, **kwargs) -> None:
|
||||||
|
"""Open the valve."""
|
||||||
|
self._ads_hub.write_by_name(self._ads_var, True, pyads.PLCTYPE_BOOL)
|
||||||
|
self._attr_is_closed = False
|
||||||
|
|
||||||
|
def close_valve(self, **kwargs) -> None:
|
||||||
|
"""Close the valve."""
|
||||||
|
self._ads_hub.write_by_name(self._ads_var, False, pyads.PLCTYPE_BOOL)
|
||||||
|
self._attr_is_closed = True
|
|
@ -55,6 +55,7 @@ async def async_setup_entry(
|
||||||
coordinator = DataUpdateCoordinator(
|
coordinator = DataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
|
config_entry=entry,
|
||||||
name="Advantage Air",
|
name="Advantage Air",
|
||||||
update_method=async_get,
|
update_method=async_get,
|
||||||
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
|
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
|
||||||
|
|
|
@ -206,7 +206,8 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||||
"""Set the HVAC Mode and State."""
|
"""Set the HVAC Mode and State."""
|
||||||
if hvac_mode == HVACMode.OFF:
|
if hvac_mode == HVACMode.OFF:
|
||||||
return await self.async_turn_off()
|
await self.async_turn_off()
|
||||||
|
return
|
||||||
if hvac_mode == HVACMode.HEAT_COOL and self.preset_mode != ADVANTAGE_AIR_MYAUTO:
|
if hvac_mode == HVACMode.HEAT_COOL and self.preset_mode != ADVANTAGE_AIR_MYAUTO:
|
||||||
raise ServiceValidationError("Heat/Cool is not supported in this mode")
|
raise ServiceValidationError("Heat/Cool is not supported in this mode")
|
||||||
await self.async_update_ac(
|
await self.async_update_ac(
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"services": {
|
"services": {
|
||||||
"set_time_to": "mdi:timer-cog"
|
"set_time_to": {
|
||||||
|
"service": "mdi:timer-cog"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""The AEMET OpenData component."""
|
"""The AEMET OpenData component."""
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aemet_opendata.exceptions import AemetError, TownNotFound
|
from aemet_opendata.exceptions import AemetError, TownNotFound
|
||||||
|
@ -13,20 +12,10 @@ from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import aiohttp_client
|
from homeassistant.helpers import aiohttp_client
|
||||||
|
|
||||||
from .const import CONF_STATION_UPDATES, PLATFORMS
|
from .const import CONF_STATION_UPDATES, PLATFORMS
|
||||||
from .coordinator import WeatherUpdateCoordinator
|
from .coordinator import AemetConfigEntry, AemetData, WeatherUpdateCoordinator
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
type AemetConfigEntry = ConfigEntry[AemetData]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class AemetData:
|
|
||||||
"""Aemet runtime data."""
|
|
||||||
|
|
||||||
name: str
|
|
||||||
coordinator: WeatherUpdateCoordinator
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: AemetConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: AemetConfigEntry) -> bool:
|
||||||
"""Set up AEMET OpenData as config entry."""
|
"""Set up AEMET OpenData as config entry."""
|
||||||
|
@ -46,7 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AemetConfigEntry) -> boo
|
||||||
except AemetError as err:
|
except AemetError as err:
|
||||||
raise ConfigEntryNotReady(err) from err
|
raise ConfigEntryNotReady(err) from err
|
||||||
|
|
||||||
weather_coordinator = WeatherUpdateCoordinator(hass, aemet)
|
weather_coordinator = WeatherUpdateCoordinator(hass, entry, aemet)
|
||||||
await weather_coordinator.async_config_entry_first_refresh()
|
await weather_coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
entry.runtime_data = AemetData(name=name, coordinator=weather_coordinator)
|
entry.runtime_data = AemetData(name=name, coordinator=weather_coordinator)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from asyncio import timeout
|
from asyncio import timeout
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Final, cast
|
from typing import Any, Final, cast
|
||||||
|
@ -19,6 +20,7 @@ from aemet_opendata.helpers import dict_nested_value
|
||||||
from aemet_opendata.interface import AEMET
|
from aemet_opendata.interface import AEMET
|
||||||
|
|
||||||
from homeassistant.components.weather import Forecast
|
from homeassistant.components.weather import Forecast
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
|
@ -29,6 +31,16 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
API_TIMEOUT: Final[int] = 120
|
API_TIMEOUT: Final[int] = 120
|
||||||
WEATHER_UPDATE_INTERVAL = timedelta(minutes=10)
|
WEATHER_UPDATE_INTERVAL = timedelta(minutes=10)
|
||||||
|
|
||||||
|
type AemetConfigEntry = ConfigEntry[AemetData]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AemetData:
|
||||||
|
"""Aemet runtime data."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
coordinator: WeatherUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||||
"""Weather data update coordinator."""
|
"""Weather data update coordinator."""
|
||||||
|
@ -36,6 +48,7 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
entry: AemetConfigEntry,
|
||||||
aemet: AEMET,
|
aemet: AEMET,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize coordinator."""
|
"""Initialize coordinator."""
|
||||||
|
@ -44,6 +57,7 @@ class WeatherUpdateCoordinator(DataUpdateCoordinator):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
|
config_entry=entry,
|
||||||
name=DOMAIN,
|
name=DOMAIN,
|
||||||
update_interval=WEATHER_UPDATE_INTERVAL,
|
update_interval=WEATHER_UPDATE_INTERVAL,
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from typing import Any
|
||||||
|
|
||||||
from aemet_opendata.const import AOD_COORDS
|
from aemet_opendata.const import AOD_COORDS
|
||||||
|
|
||||||
from homeassistant.components.diagnostics.util import async_redact_data
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
|
@ -15,7 +15,7 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import AemetConfigEntry
|
from .coordinator import AemetConfigEntry
|
||||||
|
|
||||||
TO_REDACT_CONFIG = [
|
TO_REDACT_CONFIG = [
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/aemet",
|
"documentation": "https://www.home-assistant.io/integrations/aemet",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["aemet_opendata"],
|
"loggers": ["aemet_opendata"],
|
||||||
"requirements": ["AEMET-OpenData==0.5.3"]
|
"requirements": ["AEMET-OpenData==0.5.4"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from . import AemetConfigEntry
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_API_CONDITION,
|
ATTR_API_CONDITION,
|
||||||
ATTR_API_FORECAST_CONDITION,
|
ATTR_API_FORECAST_CONDITION,
|
||||||
|
@ -87,7 +86,7 @@ from .const import (
|
||||||
ATTR_API_WIND_SPEED,
|
ATTR_API_WIND_SPEED,
|
||||||
CONDITIONS_MAP,
|
CONDITIONS_MAP,
|
||||||
)
|
)
|
||||||
from .coordinator import WeatherUpdateCoordinator
|
from .coordinator import AemetConfigEntry, WeatherUpdateCoordinator
|
||||||
from .entity import AemetEntity
|
from .entity import AemetEntity
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,6 +248,7 @@ WEATHER_SENSORS: Final[tuple[AemetSensorEntityDescription, ...]] = (
|
||||||
name="Rain",
|
name="Rain",
|
||||||
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
||||||
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
AemetSensorEntityDescription(
|
AemetSensorEntityDescription(
|
||||||
key=ATTR_API_RAIN_PROB,
|
key=ATTR_API_RAIN_PROB,
|
||||||
|
@ -263,6 +263,7 @@ WEATHER_SENSORS: Final[tuple[AemetSensorEntityDescription, ...]] = (
|
||||||
name="Snow",
|
name="Snow",
|
||||||
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
||||||
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
AemetSensorEntityDescription(
|
AemetSensorEntityDescription(
|
||||||
key=ATTR_API_SNOW_PROB,
|
key=ATTR_API_SNOW_PROB,
|
||||||
|
|
|
@ -27,9 +27,8 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import AemetConfigEntry
|
|
||||||
from .const import CONDITIONS_MAP
|
from .const import CONDITIONS_MAP
|
||||||
from .coordinator import WeatherUpdateCoordinator
|
from .coordinator import AemetConfigEntry, WeatherUpdateCoordinator
|
||||||
from .entity import AemetEntity
|
from .entity import AemetEntity
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"add_tracking": "mdi:package-variant-plus",
|
"add_tracking": {
|
||||||
"remove_tracking": "mdi:package-variant-minus"
|
"service": "mdi:package-variant-plus"
|
||||||
|
},
|
||||||
|
"remove_tracking": {
|
||||||
|
"service": "mdi:package-variant-minus"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,7 @@ from __future__ import annotations
|
||||||
from homeassistant.components.alarm_control_panel import (
|
from homeassistant.components.alarm_control_panel import (
|
||||||
AlarmControlPanelEntity,
|
AlarmControlPanelEntity,
|
||||||
AlarmControlPanelEntityFeature,
|
AlarmControlPanelEntityFeature,
|
||||||
)
|
AlarmControlPanelState,
|
||||||
from homeassistant.const import (
|
|
||||||
STATE_ALARM_ARMED_AWAY,
|
|
||||||
STATE_ALARM_ARMED_HOME,
|
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
|
||||||
STATE_ALARM_DISARMED,
|
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
|
@ -65,37 +60,37 @@ class AgentBaseStation(AlarmControlPanelEntity):
|
||||||
self._attr_available = self._client.is_available
|
self._attr_available = self._client.is_available
|
||||||
armed = self._client.is_armed
|
armed = self._client.is_armed
|
||||||
if armed is None:
|
if armed is None:
|
||||||
self._attr_state = None
|
self._attr_alarm_state = None
|
||||||
return
|
return
|
||||||
if armed:
|
if armed:
|
||||||
prof = (await self._client.get_active_profile()).lower()
|
prof = (await self._client.get_active_profile()).lower()
|
||||||
self._attr_state = STATE_ALARM_ARMED_AWAY
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
|
||||||
if prof == CONF_HOME_MODE_NAME:
|
if prof == CONF_HOME_MODE_NAME:
|
||||||
self._attr_state = STATE_ALARM_ARMED_HOME
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
|
||||||
elif prof == CONF_NIGHT_MODE_NAME:
|
elif prof == CONF_NIGHT_MODE_NAME:
|
||||||
self._attr_state = STATE_ALARM_ARMED_NIGHT
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT
|
||||||
else:
|
else:
|
||||||
self._attr_state = STATE_ALARM_DISARMED
|
self._attr_alarm_state = AlarmControlPanelState.DISARMED
|
||||||
|
|
||||||
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||||
"""Send disarm command."""
|
"""Send disarm command."""
|
||||||
await self._client.disarm()
|
await self._client.disarm()
|
||||||
self._attr_state = STATE_ALARM_DISARMED
|
self._attr_alarm_state = AlarmControlPanelState.DISARMED
|
||||||
|
|
||||||
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||||
"""Send arm away command. Uses custom mode."""
|
"""Send arm away command. Uses custom mode."""
|
||||||
await self._client.arm()
|
await self._client.arm()
|
||||||
await self._client.set_active_profile(CONF_AWAY_MODE_NAME)
|
await self._client.set_active_profile(CONF_AWAY_MODE_NAME)
|
||||||
self._attr_state = STATE_ALARM_ARMED_AWAY
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
|
||||||
|
|
||||||
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
||||||
"""Send arm home command. Uses custom mode."""
|
"""Send arm home command. Uses custom mode."""
|
||||||
await self._client.arm()
|
await self._client.arm()
|
||||||
await self._client.set_active_profile(CONF_HOME_MODE_NAME)
|
await self._client.set_active_profile(CONF_HOME_MODE_NAME)
|
||||||
self._attr_state = STATE_ALARM_ARMED_HOME
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
|
||||||
|
|
||||||
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
||||||
"""Send arm night command. Uses custom mode."""
|
"""Send arm night command. Uses custom mode."""
|
||||||
await self._client.arm()
|
await self._client.arm()
|
||||||
await self._client.set_active_profile(CONF_NIGHT_MODE_NAME)
|
await self._client.set_active_profile(CONF_NIGHT_MODE_NAME)
|
||||||
self._attr_state = STATE_ALARM_ARMED_NIGHT
|
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT
|
||||||
|
|
|
@ -59,7 +59,7 @@ async def async_setup_entry(
|
||||||
|
|
||||||
platform = async_get_current_platform()
|
platform = async_get_current_platform()
|
||||||
for service, method in CAMERA_SERVICES.items():
|
for service, method in CAMERA_SERVICES.items():
|
||||||
platform.async_register_entity_service(service, {}, method)
|
platform.async_register_entity_service(service, None, method)
|
||||||
|
|
||||||
|
|
||||||
class AgentCamera(MjpegCamera):
|
class AgentCamera(MjpegCamera):
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
{
|
{
|
||||||
"services": {
|
"services": {
|
||||||
"start_recording": "mdi:record-rec",
|
"start_recording": {
|
||||||
"stop_recording": "mdi:stop",
|
"service": "mdi:record-rec"
|
||||||
"enable_alerts": "mdi:bell-alert",
|
},
|
||||||
"disable_alerts": "mdi:bell-off",
|
"stop_recording": {
|
||||||
"snapshot": "mdi:camera"
|
"service": "mdi:stop"
|
||||||
|
},
|
||||||
|
"enable_alerts": {
|
||||||
|
"service": "mdi:bell-alert"
|
||||||
|
},
|
||||||
|
"disable_alerts": {
|
||||||
|
"service": "mdi:bell-off"
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"service": "mdi:camera"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/agent_dvr",
|
"documentation": "https://www.home-assistant.io/integrations/agent_dvr",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["agent"],
|
"loggers": ["agent"],
|
||||||
"requirements": ["agent-py==0.0.23"]
|
"requirements": ["agent-py==0.0.24"]
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue