mirror of
https://github.com/home-assistant/core.git
synced 2025-10-01 07:49:26 +00:00
Compare commits
472 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0f39296251 | ||
![]() |
dd0fd36049 | ||
![]() |
30a391b88b | ||
![]() |
71803cbdef | ||
![]() |
f5eafbe760 | ||
![]() |
52f710528f | ||
![]() |
38b729b00a | ||
![]() |
5dae7f8451 | ||
![]() |
6a297b3758 | ||
![]() |
ab7afbdaf7 | ||
![]() |
0763503151 | ||
![]() |
4ead87270e | ||
![]() |
1634592d90 | ||
![]() |
ddddd8566d | ||
![]() |
5cf2043c04 | ||
![]() |
43777ace20 | ||
![]() |
a7e5cc31c3 | ||
![]() |
aa6520cac1 | ||
![]() |
af10cd315e | ||
![]() |
ef28bcaa9c | ||
![]() |
ff3bfade31 | ||
![]() |
4eafd8adf7 | ||
![]() |
cb5de0e090 | ||
![]() |
254394ecab | ||
![]() |
e4e0c37a8c | ||
![]() |
e27d5cd9fb | ||
![]() |
6f449cd383 | ||
![]() |
d47cef4ba2 | ||
![]() |
a8da03912e | ||
![]() |
8f233b822f | ||
![]() |
060c6c89e3 | ||
![]() |
96dc0319d8 | ||
![]() |
08b0c1178b | ||
![]() |
252c724602 | ||
![]() |
c529bcca9b | ||
![]() |
9b94d128ad | ||
![]() |
9c224e0515 | ||
![]() |
899e7bfb5a | ||
![]() |
ef5f4b2aca | ||
![]() |
e86fb3fc5c | ||
![]() |
c63ec698a1 | ||
![]() |
71aaf2d809 | ||
![]() |
400602a8b3 | ||
![]() |
4a32a0f1da | ||
![]() |
0cf9268ca8 | ||
![]() |
fb93b79b12 | ||
![]() |
eff9b2a1a0 | ||
![]() |
4dbbf93af9 | ||
![]() |
3d73f166be | ||
![]() |
0e6aacb440 | ||
![]() |
cc443ff37a | ||
![]() |
2cfa0af532 | ||
![]() |
83fb5e5071 | ||
![]() |
955c94e313 | ||
![]() |
b892dbc6ea | ||
![]() |
3566803d2e | ||
![]() |
774b1d1663 | ||
![]() |
90dd796644 | ||
![]() |
a473ae6711 | ||
![]() |
be99f3bf32 | ||
![]() |
5047635224 | ||
![]() |
e6ed2f0377 | ||
![]() |
b88f56cbfb | ||
![]() |
06216a8a45 | ||
![]() |
f085a0c54a | ||
![]() |
b783aab41b | ||
![]() |
12b408219e | ||
![]() |
6cafc9aaef | ||
![]() |
f5cbc9d208 | ||
![]() |
dd1608db0d | ||
![]() |
f2f03cf552 | ||
![]() |
977f1a6916 | ||
![]() |
ffefdcfe22 | ||
![]() |
f4eb1f0652 | ||
![]() |
23668f3c5e | ||
![]() |
6208d8c911 | ||
![]() |
d0dad4bfd6 | ||
![]() |
7330e30fd3 | ||
![]() |
a9cbd355ca | ||
![]() |
3e0eaa3c87 | ||
![]() |
98f68f4798 | ||
![]() |
0e3c1dc031 | ||
![]() |
9508c51403 | ||
![]() |
531207e005 | ||
![]() |
952aa02e37 | ||
![]() |
3e0ccd2e86 | ||
![]() |
bcd1eb952c | ||
![]() |
01bf4daf37 | ||
![]() |
0186ce7896 | ||
![]() |
f42804805c | ||
![]() |
eee0a6e9f4 | ||
![]() |
0e6b905cdf | ||
![]() |
d59209ff47 | ||
![]() |
ad8cf2d0d0 | ||
![]() |
fe0db80fb8 | ||
![]() |
ef61118d49 | ||
![]() |
de54659097 | ||
![]() |
ad3c5240c2 | ||
![]() |
0f9790f5f1 | ||
![]() |
68e86c5e3a | ||
![]() |
1cd0e764b6 | ||
![]() |
d45c386149 | ||
![]() |
dd3cd95954 | ||
![]() |
188ca630de | ||
![]() |
ffafcf27a8 | ||
![]() |
21098bc3e5 | ||
![]() |
1f9f5bfaa8 | ||
![]() |
312af53935 | ||
![]() |
3c2df7f8f2 | ||
![]() |
42cb5a5239 | ||
![]() |
d832ce0b26 | ||
![]() |
f32ae95ef4 | ||
![]() |
de2f506585 | ||
![]() |
f7ae78f78e | ||
![]() |
5bedc4ede2 | ||
![]() |
03a090e384 | ||
![]() |
dd232a3507 | ||
![]() |
03a9e3284c | ||
![]() |
c08ca8a439 | ||
![]() |
bf16b50679 | ||
![]() |
5a1b0edd96 | ||
![]() |
1477087c71 | ||
![]() |
4a2236fe85 | ||
![]() |
95cefd1acc | ||
![]() |
5ce31cb383 | ||
![]() |
ff391e538a | ||
![]() |
28a2c9c653 | ||
![]() |
369ffe2288 | ||
![]() |
5f72ad8da6 | ||
![]() |
00c38c5f70 | ||
![]() |
18a4829314 | ||
![]() |
c629e7dc0e | ||
![]() |
73c52e668e | ||
![]() |
6cafc45d2b | ||
![]() |
4f767dd3ef | ||
![]() |
c89975adf6 | ||
![]() |
867630a4a7 | ||
![]() |
a6d5ed0160 | ||
![]() |
f93e4e3de7 | ||
![]() |
f5a6c3484d | ||
![]() |
b8afb9277a | ||
![]() |
262ed9ed2a | ||
![]() |
f1e58d0784 | ||
![]() |
6c6318d18f | ||
![]() |
3dc6612cd9 | ||
![]() |
a38db1f677 | ||
![]() |
558cccc68c | ||
![]() |
b598ff94d1 | ||
![]() |
c267946284 | ||
![]() |
07ce284acd | ||
![]() |
6c4b4ad1e0 | ||
![]() |
815d153e55 | ||
![]() |
eac03ef4be | ||
![]() |
a38e075bda | ||
![]() |
cced74740f | ||
![]() |
1236c2b91e | ||
![]() |
d54d7c6958 | ||
![]() |
9365ba3fcf | ||
![]() |
5650b390b9 | ||
![]() |
8f4d3146c1 | ||
![]() |
2647296475 | ||
![]() |
6d311a31dd | ||
![]() |
4bbc0a03ca | ||
![]() |
16670a38a4 | ||
![]() |
eb8e8d00a6 | ||
![]() |
d5f4dfdd6b | ||
![]() |
4a0a56ebdc | ||
![]() |
6990c70123 | ||
![]() |
bb68e7a532 | ||
![]() |
bb3592baa0 | ||
![]() |
1fa996ed68 | ||
![]() |
2a3c94bad0 | ||
![]() |
3ee05ad4bb | ||
![]() |
44425a184e | ||
![]() |
28c2f9caa9 | ||
![]() |
2a36adae46 | ||
![]() |
46985bba0d | ||
![]() |
3f4a7ec396 | ||
![]() |
ad9f4db983 | ||
![]() |
0e2fa7700d | ||
![]() |
109f083c5d | ||
![]() |
fb22f6c301 | ||
![]() |
aec2fe86e4 | ||
![]() |
763ed0dc7b | ||
![]() |
baf7fb7264 | ||
![]() |
f150c9c65c | ||
![]() |
d979648c01 | ||
![]() |
9226589bcd | ||
![]() |
edfe8e1583 | ||
![]() |
b36b1dbc70 | ||
![]() |
253c848692 | ||
![]() |
7a6ac578b4 | ||
![]() |
e616ab5fb2 | ||
![]() |
3c59791b2e | ||
![]() |
b50281a917 | ||
![]() |
2d002f3ef6 | ||
![]() |
6180f7bd64 | ||
![]() |
45241e57ca | ||
![]() |
cd57b764ce | ||
![]() |
c2a9aba467 | ||
![]() |
5c2bd8b743 | ||
![]() |
513abcb7e5 | ||
![]() |
1ff245d9c2 | ||
![]() |
2360fd4141 | ||
![]() |
95de94e53f | ||
![]() |
ea23ffedfe | ||
![]() |
bf4b099f11 | ||
![]() |
b8fdebd05c | ||
![]() |
181b2803cd | ||
![]() |
0e3dc7976c | ||
![]() |
c8d4cf08d9 | ||
![]() |
df67ab995f | ||
![]() |
e0f2fa33df | ||
![]() |
884c346bdf | ||
![]() |
c218ff5a75 | ||
![]() |
fa43a218d2 | ||
![]() |
f4cc64d289 | ||
![]() |
4c31829832 | ||
![]() |
ff32c1c3e9 | ||
![]() |
c21a2eab22 | ||
![]() |
df2351b920 | ||
![]() |
4332cbe112 | ||
![]() |
f9a7c64106 | ||
![]() |
49ebea2be3 | ||
![]() |
b09a9fc81a | ||
![]() |
fa60e9b03b | ||
![]() |
0b2a8bf79a | ||
![]() |
087b672449 | ||
![]() |
d3f9408650 | ||
![]() |
6e6ad94df6 | ||
![]() |
e344c2ea64 | ||
![]() |
ab8c50895e | ||
![]() |
f0472f2dc2 | ||
![]() |
0249daef2e | ||
![]() |
8d2e72cdf6 | ||
![]() |
52ac7285a7 | ||
![]() |
2a3d688923 | ||
![]() |
ca3a22b5a3 | ||
![]() |
912cda4e6f | ||
![]() |
c79b3df73f | ||
![]() |
8423d18d8d | ||
![]() |
9d87c1ab1a | ||
![]() |
f95c3e265d | ||
![]() |
66402b9b38 | ||
![]() |
99877c32b1 | ||
![]() |
4510e83150 | ||
![]() |
252d934caa | ||
![]() |
e8bd1b9216 | ||
![]() |
99d732b974 | ||
![]() |
05e7238c45 | ||
![]() |
677c276b41 | ||
![]() |
991afccbd4 | ||
![]() |
d5e606640c | ||
![]() |
ca1c696f54 | ||
![]() |
78e5878247 | ||
![]() |
470537bc5f | ||
![]() |
64556f6f69 | ||
![]() |
2785b067e3 | ||
![]() |
a129bc05ae | ||
![]() |
197736f66b | ||
![]() |
6d4fa76107 | ||
![]() |
ba2558790d | ||
![]() |
79f6d55fe8 | ||
![]() |
403b4a2e0b | ||
![]() |
8272c71811 | ||
![]() |
699ca44260 | ||
![]() |
5893f6b14b | ||
![]() |
a7b08c48f3 | ||
![]() |
0148708613 | ||
![]() |
81cef9a281 | ||
![]() |
2bb29485be | ||
![]() |
57820be92a | ||
![]() |
e18bea0215 | ||
![]() |
49c2a4a4e3 | ||
![]() |
ebc4804e04 | ||
![]() |
ffc9bcb4d7 | ||
![]() |
d82d7fa2e9 | ||
![]() |
e87fab6b5f | ||
![]() |
663db747e9 | ||
![]() |
57998f6f0f | ||
![]() |
edbb995fff | ||
![]() |
312903025d | ||
![]() |
0ae5c325fe | ||
![]() |
b6d9454b54 | ||
![]() |
85328399e0 | ||
![]() |
836413a4a8 | ||
![]() |
d16d44d3e7 | ||
![]() |
c2ac8e813a | ||
![]() |
37687561c0 | ||
![]() |
acf41d03db | ||
![]() |
92d373055f | ||
![]() |
a309a00929 | ||
![]() |
c00f04221f | ||
![]() |
414559f018 | ||
![]() |
55be5bf880 | ||
![]() |
7b37dcd8ed | ||
![]() |
e36bdd717a | ||
![]() |
fa650b648c | ||
![]() |
661101df08 | ||
![]() |
ecbcdee934 | ||
![]() |
eb77b94315 | ||
![]() |
6ab14a3729 | ||
![]() |
f81464161a | ||
![]() |
3461f3a1ed | ||
![]() |
ac2310e7f9 | ||
![]() |
0ed7bc3b8e | ||
![]() |
aee5c16803 | ||
![]() |
d8e3e9abaa | ||
![]() |
5f0816ea25 | ||
![]() |
6a6037790f | ||
![]() |
d2b0c35319 | ||
![]() |
d707a1b072 | ||
![]() |
ca12db9271 | ||
![]() |
346a4b399d | ||
![]() |
2090252936 | ||
![]() |
a28091e94a | ||
![]() |
ae8cb0ccdf | ||
![]() |
06a608e342 | ||
![]() |
9af95e8577 | ||
![]() |
c3c5cc9ae7 | ||
![]() |
5db1a67c20 | ||
![]() |
1a4199c485 | ||
![]() |
8cb1d630c8 | ||
![]() |
f275b7e5ed | ||
![]() |
c9592c1447 | ||
![]() |
ff2367fffb | ||
![]() |
4c9303bbd5 | ||
![]() |
84712d2f40 | ||
![]() |
5a2aabea9c | ||
![]() |
23045af4a7 | ||
![]() |
29a9781bf7 | ||
![]() |
877eddf43d | ||
![]() |
9451920ab5 | ||
![]() |
62f2ee5f60 | ||
![]() |
c8c81d493d | ||
![]() |
d33a3ca90f | ||
![]() |
5b4d2aed64 | ||
![]() |
242aff9269 | ||
![]() |
445ef861c0 | ||
![]() |
03c906a2f1 | ||
![]() |
e0d2e5dcb0 | ||
![]() |
88e3e73bb4 | ||
![]() |
3aa1bcbb77 | ||
![]() |
5c1dc60505 | ||
![]() |
f6ce5f2d05 | ||
![]() |
f973b35cef | ||
![]() |
4e08aa8b05 | ||
![]() |
8e917ccf73 | ||
![]() |
0b62011626 | ||
![]() |
08aa4b098c | ||
![]() |
5123baba3f | ||
![]() |
ede0cfaeb8 | ||
![]() |
34e44e7f3a | ||
![]() |
0cb27ff236 | ||
![]() |
cb450dcebd | ||
![]() |
661570dfad | ||
![]() |
05abf37046 | ||
![]() |
7c79adad8f | ||
![]() |
e0769f9ad4 | ||
![]() |
7d23a734fc | ||
![]() |
4e4fd90455 | ||
![]() |
4517f0d59a | ||
![]() |
c1ceab09e5 | ||
![]() |
609263e1bb | ||
![]() |
f02c5f66d6 | ||
![]() |
82c8f18bc7 | ||
![]() |
a9d16d4276 | ||
![]() |
505de3dce3 | ||
![]() |
52a4c16980 | ||
![]() |
a2ac335222 | ||
![]() |
cd79720a14 | ||
![]() |
576970d1ad | ||
![]() |
9146f76b01 | ||
![]() |
e97d21aec0 | ||
![]() |
097b056324 | ||
![]() |
aece76f6cd | ||
![]() |
7bbffa6e6d | ||
![]() |
ff582721dd | ||
![]() |
3910ab6cab | ||
![]() |
5c83367bb0 | ||
![]() |
433b89de50 | ||
![]() |
4c32fd12fc | ||
![]() |
a3e2504470 | ||
![]() |
d98432c328 | ||
![]() |
1da35e2939 | ||
![]() |
0c49c8578b | ||
![]() |
abd1909e2b | ||
![]() |
86d48c608e | ||
![]() |
a278cf3db2 | ||
![]() |
2cda7bf1e7 | ||
![]() |
7ac014744c | ||
![]() |
51b9afe3c1 | ||
![]() |
397238372e | ||
![]() |
682fcec99e | ||
![]() |
41cd3ba532 | ||
![]() |
426f546c2f | ||
![]() |
2f1824774f | ||
![]() |
999c5443c1 | ||
![]() |
7ec7306ea8 | ||
![]() |
8d68f34650 | ||
![]() |
c1908d16b5 | ||
![]() |
40356b4fc5 | ||
![]() |
f4b3760a1a | ||
![]() |
fa63dc1e25 | ||
![]() |
b9ad40ed38 | ||
![]() |
77b3f31e9b | ||
![]() |
451c6c25cd | ||
![]() |
af021b1c81 | ||
![]() |
4e3b079a29 | ||
![]() |
9a099bdf0a | ||
![]() |
cf8dfdae47 | ||
![]() |
6e95b90f42 | ||
![]() |
d36259f067 | ||
![]() |
d62bb9ed47 | ||
![]() |
ef54f33af7 | ||
![]() |
1391f90a30 | ||
![]() |
2889067ece | ||
![]() |
f4bf66aecd | ||
![]() |
2f80489428 | ||
![]() |
b6e69cd370 | ||
![]() |
f9634f0232 | ||
![]() |
6affb27711 | ||
![]() |
5ec76af875 | ||
![]() |
5b41680506 | ||
![]() |
4f81109304 | ||
![]() |
04763c5bfb | ||
![]() |
e5e38edcb2 | ||
![]() |
e86919a997 | ||
![]() |
d04479044c | ||
![]() |
7737387efe | ||
![]() |
743166d284 | ||
![]() |
5dd031af17 | ||
![]() |
750ed2facd | ||
![]() |
aa972b0005 | ||
![]() |
628f77f8f2 | ||
![]() |
9db3900cff | ||
![]() |
fd5895118e | ||
![]() |
607cdfdd32 | ||
![]() |
460857a765 | ||
![]() |
6bd55011a8 | ||
![]() |
e2a113a2de | ||
![]() |
86f61b8e55 | ||
![]() |
f3fed5647e | ||
![]() |
992daa4a44 | ||
![]() |
26d7b2164e | ||
![]() |
31d150794d | ||
![]() |
7e6e36db15 | ||
![]() |
4f0997f6e9 | ||
![]() |
94b6ab2862 | ||
![]() |
11a25157c1 | ||
![]() |
ff92a8b260 | ||
![]() |
1fe26c77e0 | ||
![]() |
00d5e5cfb2 | ||
![]() |
c968e455a9 | ||
![]() |
a3dd9979d2 | ||
![]() |
6e97975ff8 | ||
![]() |
af7c01f957 | ||
![]() |
29533d8d4d | ||
![]() |
374a8157e7 | ||
![]() |
40fc72aac2 | ||
![]() |
b8fab33e69 | ||
![]() |
221d5205e4 | ||
![]() |
77ebda0c20 | ||
![]() |
ac30e5799c | ||
![]() |
f9a0b4b3cf | ||
![]() |
233568ac29 | ||
![]() |
76b0302c7f | ||
![]() |
8bc542776b | ||
![]() |
5f5cb8bea8 | ||
![]() |
da761fdd39 | ||
![]() |
22415ce49a | ||
![]() |
19be4a5d6d |
29
.coveragerc
29
.coveragerc
@@ -8,15 +8,6 @@ omit =
|
|||||||
homeassistant/scripts/*.py
|
homeassistant/scripts/*.py
|
||||||
|
|
||||||
# omit pieces of code that rely on external devices being present
|
# omit pieces of code that rely on external devices being present
|
||||||
homeassistant/components/abode/__init__.py
|
|
||||||
homeassistant/components/abode/alarm_control_panel.py
|
|
||||||
homeassistant/components/abode/binary_sensor.py
|
|
||||||
homeassistant/components/abode/camera.py
|
|
||||||
homeassistant/components/abode/cover.py
|
|
||||||
homeassistant/components/abode/light.py
|
|
||||||
homeassistant/components/abode/lock.py
|
|
||||||
homeassistant/components/abode/sensor.py
|
|
||||||
homeassistant/components/abode/switch.py
|
|
||||||
homeassistant/components/acer_projector/switch.py
|
homeassistant/components/acer_projector/switch.py
|
||||||
homeassistant/components/actiontec/device_tracker.py
|
homeassistant/components/actiontec/device_tracker.py
|
||||||
homeassistant/components/adguard/__init__.py
|
homeassistant/components/adguard/__init__.py
|
||||||
@@ -33,7 +24,6 @@ omit =
|
|||||||
homeassistant/components/airvisual/sensor.py
|
homeassistant/components/airvisual/sensor.py
|
||||||
homeassistant/components/aladdin_connect/cover.py
|
homeassistant/components/aladdin_connect/cover.py
|
||||||
homeassistant/components/alarmdecoder/*
|
homeassistant/components/alarmdecoder/*
|
||||||
homeassistant/components/alarmdotcom/alarm_control_panel.py
|
|
||||||
homeassistant/components/alpha_vantage/sensor.py
|
homeassistant/components/alpha_vantage/sensor.py
|
||||||
homeassistant/components/amazon_polly/tts.py
|
homeassistant/components/amazon_polly/tts.py
|
||||||
homeassistant/components/ambiclimate/climate.py
|
homeassistant/components/ambiclimate/climate.py
|
||||||
@@ -85,6 +75,7 @@ omit =
|
|||||||
homeassistant/components/bluetooth_tracker/*
|
homeassistant/components/bluetooth_tracker/*
|
||||||
homeassistant/components/bme280/sensor.py
|
homeassistant/components/bme280/sensor.py
|
||||||
homeassistant/components/bme680/sensor.py
|
homeassistant/components/bme680/sensor.py
|
||||||
|
homeassistant/components/bmp280/sensor.py
|
||||||
homeassistant/components/bmw_connected_drive/*
|
homeassistant/components/bmw_connected_drive/*
|
||||||
homeassistant/components/bom/camera.py
|
homeassistant/components/bom/camera.py
|
||||||
homeassistant/components/bom/sensor.py
|
homeassistant/components/bom/sensor.py
|
||||||
@@ -93,9 +84,6 @@ omit =
|
|||||||
homeassistant/components/broadlink/remote.py
|
homeassistant/components/broadlink/remote.py
|
||||||
homeassistant/components/broadlink/sensor.py
|
homeassistant/components/broadlink/sensor.py
|
||||||
homeassistant/components/broadlink/switch.py
|
homeassistant/components/broadlink/switch.py
|
||||||
homeassistant/components/brother/__init__.py
|
|
||||||
homeassistant/components/brother/sensor.py
|
|
||||||
homeassistant/components/brother/const.py
|
|
||||||
homeassistant/components/brottsplatskartan/sensor.py
|
homeassistant/components/brottsplatskartan/sensor.py
|
||||||
homeassistant/components/browser/*
|
homeassistant/components/browser/*
|
||||||
homeassistant/components/brunt/cover.py
|
homeassistant/components/brunt/cover.py
|
||||||
@@ -242,7 +230,11 @@ omit =
|
|||||||
homeassistant/components/foscam/const.py
|
homeassistant/components/foscam/const.py
|
||||||
homeassistant/components/foursquare/*
|
homeassistant/components/foursquare/*
|
||||||
homeassistant/components/free_mobile/notify.py
|
homeassistant/components/free_mobile/notify.py
|
||||||
homeassistant/components/freebox/*
|
homeassistant/components/freebox/__init__.py
|
||||||
|
homeassistant/components/freebox/device_tracker.py
|
||||||
|
homeassistant/components/freebox/router.py
|
||||||
|
homeassistant/components/freebox/sensor.py
|
||||||
|
homeassistant/components/freebox/switch.py
|
||||||
homeassistant/components/fritz/device_tracker.py
|
homeassistant/components/fritz/device_tracker.py
|
||||||
homeassistant/components/fritzbox/*
|
homeassistant/components/fritzbox/*
|
||||||
homeassistant/components/fritzbox_callmonitor/sensor.py
|
homeassistant/components/fritzbox_callmonitor/sensor.py
|
||||||
@@ -433,6 +425,7 @@ omit =
|
|||||||
homeassistant/components/minecraft_server/__init__.py
|
homeassistant/components/minecraft_server/__init__.py
|
||||||
homeassistant/components/minecraft_server/binary_sensor.py
|
homeassistant/components/minecraft_server/binary_sensor.py
|
||||||
homeassistant/components/minecraft_server/const.py
|
homeassistant/components/minecraft_server/const.py
|
||||||
|
homeassistant/components/minecraft_server/helpers.py
|
||||||
homeassistant/components/minecraft_server/sensor.py
|
homeassistant/components/minecraft_server/sensor.py
|
||||||
homeassistant/components/minio/*
|
homeassistant/components/minio/*
|
||||||
homeassistant/components/mitemp_bt/sensor.py
|
homeassistant/components/mitemp_bt/sensor.py
|
||||||
@@ -441,7 +434,6 @@ omit =
|
|||||||
homeassistant/components/mochad/*
|
homeassistant/components/mochad/*
|
||||||
homeassistant/components/modbus/*
|
homeassistant/components/modbus/*
|
||||||
homeassistant/components/modem_callerid/sensor.py
|
homeassistant/components/modem_callerid/sensor.py
|
||||||
homeassistant/components/mopar/*
|
|
||||||
homeassistant/components/mpchc/media_player.py
|
homeassistant/components/mpchc/media_player.py
|
||||||
homeassistant/components/mpd/media_player.py
|
homeassistant/components/mpd/media_player.py
|
||||||
homeassistant/components/mqtt_room/sensor.py
|
homeassistant/components/mqtt_room/sensor.py
|
||||||
@@ -450,7 +442,6 @@ omit =
|
|||||||
homeassistant/components/mychevy/*
|
homeassistant/components/mychevy/*
|
||||||
homeassistant/components/mycroft/*
|
homeassistant/components/mycroft/*
|
||||||
homeassistant/components/mycroft/notify.py
|
homeassistant/components/mycroft/notify.py
|
||||||
homeassistant/components/myq/cover.py
|
|
||||||
homeassistant/components/mysensors/*
|
homeassistant/components/mysensors/*
|
||||||
homeassistant/components/mystrom/binary_sensor.py
|
homeassistant/components/mystrom/binary_sensor.py
|
||||||
homeassistant/components/mystrom/light.py
|
homeassistant/components/mystrom/light.py
|
||||||
@@ -476,6 +467,7 @@ omit =
|
|||||||
homeassistant/components/netgear_lte/*
|
homeassistant/components/netgear_lte/*
|
||||||
homeassistant/components/netio/switch.py
|
homeassistant/components/netio/switch.py
|
||||||
homeassistant/components/neurio_energy/sensor.py
|
homeassistant/components/neurio_energy/sensor.py
|
||||||
|
homeassistant/components/nextcloud/*
|
||||||
homeassistant/components/nfandroidtv/notify.py
|
homeassistant/components/nfandroidtv/notify.py
|
||||||
homeassistant/components/niko_home_control/light.py
|
homeassistant/components/niko_home_control/light.py
|
||||||
homeassistant/components/nilu/air_quality.py
|
homeassistant/components/nilu/air_quality.py
|
||||||
@@ -597,7 +589,9 @@ omit =
|
|||||||
homeassistant/components/ring/camera.py
|
homeassistant/components/ring/camera.py
|
||||||
homeassistant/components/ripple/sensor.py
|
homeassistant/components/ripple/sensor.py
|
||||||
homeassistant/components/rocketchat/notify.py
|
homeassistant/components/rocketchat/notify.py
|
||||||
homeassistant/components/roku/*
|
homeassistant/components/roku/__init__.py
|
||||||
|
homeassistant/components/roku/media_player.py
|
||||||
|
homeassistant/components/roku/remote.py
|
||||||
homeassistant/components/roomba/vacuum.py
|
homeassistant/components/roomba/vacuum.py
|
||||||
homeassistant/components/route53/*
|
homeassistant/components/route53/*
|
||||||
homeassistant/components/rova/sensor.py
|
homeassistant/components/rova/sensor.py
|
||||||
@@ -614,6 +608,7 @@ omit =
|
|||||||
homeassistant/components/saj/sensor.py
|
homeassistant/components/saj/sensor.py
|
||||||
homeassistant/components/salt/device_tracker.py
|
homeassistant/components/salt/device_tracker.py
|
||||||
homeassistant/components/satel_integra/*
|
homeassistant/components/satel_integra/*
|
||||||
|
homeassistant/components/schluter/*
|
||||||
homeassistant/components/scrape/sensor.py
|
homeassistant/components/scrape/sensor.py
|
||||||
homeassistant/components/scsgate/*
|
homeassistant/components/scsgate/*
|
||||||
homeassistant/components/scsgate/cover.py
|
homeassistant/components/scsgate/cover.py
|
||||||
|
@@ -2,9 +2,15 @@
|
|||||||
.git
|
.git
|
||||||
.github
|
.github
|
||||||
config
|
config
|
||||||
|
docs
|
||||||
|
|
||||||
|
# Development
|
||||||
|
.devcontainer
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Test related files
|
# Test related files
|
||||||
.tox
|
.tox
|
||||||
|
tests
|
||||||
|
|
||||||
# Other virtualization methods
|
# Other virtualization methods
|
||||||
venv
|
venv
|
||||||
|
49
.github/ISSUE_TEMPLATE.md
vendored
Normal file
49
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!-- READ THIS FIRST:
|
||||||
|
- If you need additional help with this template, please refer to https://www.home-assistant.io/help/reporting_issues/
|
||||||
|
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/core/releases
|
||||||
|
- Do not report issues for integrations if you are using custom components or integrations.
|
||||||
|
- Provide as many details as possible. Paste logs, configuration samples and code into the backticks.
|
||||||
|
DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed without comment.
|
||||||
|
-->
|
||||||
|
## The problem
|
||||||
|
<!--
|
||||||
|
Describe the issue you are experiencing here to communicate to the
|
||||||
|
maintainers. Tell us what you were trying to do and what happened.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
<!--
|
||||||
|
Provide details about the versions you are using, which helps us to reproduce
|
||||||
|
and find the issue quicker. Version information is found in the
|
||||||
|
Home Assistant frontend: Developer tools -> Info.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Home Assistant Core release with the issue:
|
||||||
|
- Last working Home Assistant Core release (if known):
|
||||||
|
- Operating environment (Home Assistant/Supervised/Docker/venv):
|
||||||
|
- Integration causing this issue:
|
||||||
|
- Link to integration documentation on our website:
|
||||||
|
|
||||||
|
## Problem-relevant `configuration.yaml`
|
||||||
|
<!--
|
||||||
|
An example configuration that caused the problem for you. Fill this out even
|
||||||
|
if it seems unimportant to you. Please be sure to remove personal information
|
||||||
|
like passwords, private URLs and other credentials.
|
||||||
|
-->
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Traceback/Error logs
|
||||||
|
<!--
|
||||||
|
If you come across any trace or error logs, please provide them.
|
||||||
|
-->
|
||||||
|
|
||||||
|
```txt
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional information
|
||||||
|
|
14
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
14
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: Report a bug with Home Assistant
|
name: Report a bug with Home Assistant Core
|
||||||
about: Report an issue with Home Assistant
|
about: Report an issue with Home Assistant Core
|
||||||
---
|
---
|
||||||
<!-- READ THIS FIRST:
|
<!-- READ THIS FIRST:
|
||||||
- If you need additional help with this template, please refer to https://www.home-assistant.io/help/reporting_issues/
|
- If you need additional help with this template, please refer to https://www.home-assistant.io/help/reporting_issues/
|
||||||
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/home-assistant/releases
|
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/core/releases
|
||||||
- Do not report issues for integrations if you are using custom components or integrations.
|
- Do not report issues for integrations if you are using custom components or integrations.
|
||||||
- Provide as many details as possible. Paste logs, configuration samples and code into the backticks.
|
- Provide as many details as possible. Paste logs, configuration samples and code into the backticks.
|
||||||
DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed without comment.
|
DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed without comment.
|
||||||
@@ -12,7 +12,7 @@ about: Report an issue with Home Assistant
|
|||||||
## The problem
|
## The problem
|
||||||
<!--
|
<!--
|
||||||
Describe the issue you are experiencing here to communicate to the
|
Describe the issue you are experiencing here to communicate to the
|
||||||
maintainers. Tell us what you were trying to do and what happened instead.
|
maintainers. Tell us what you were trying to do and what happened.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
@@ -23,9 +23,9 @@ about: Report an issue with Home Assistant
|
|||||||
Home Assistant frontend: Developer tools -> Info.
|
Home Assistant frontend: Developer tools -> Info.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- Home Assistant release with the issue:
|
- Home Assistant Core release with the issue:
|
||||||
- Last working Home Assistant release (if known):
|
- Last working Home Assistant Core release (if known):
|
||||||
- Operating environment (Hass.io/Docker/Windows/etc.):
|
- Operating environment (Home Assistant/Supervised/Docker/venv):
|
||||||
- Integration causing this issue:
|
- Integration causing this issue:
|
||||||
- Link to integration documentation on our website:
|
- Link to integration documentation on our website:
|
||||||
|
|
||||||
|
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -57,6 +57,7 @@ limitPerRun: 30
|
|||||||
# Handle pull requests a little bit faster and with an adjusted comment.
|
# Handle pull requests a little bit faster and with an adjusted comment.
|
||||||
pulls:
|
pulls:
|
||||||
daysUntilStale: 30
|
daysUntilStale: 30
|
||||||
|
exemptProjects: false
|
||||||
markComment: >
|
markComment: >
|
||||||
There hasn't been any activity on this pull request recently. This pull
|
There hasn't been any activity on this pull request recently. This pull
|
||||||
request has been automatically marked as stale because of that and will
|
request has been automatically marked as stale because of that and will
|
||||||
|
@@ -59,3 +59,17 @@ repos:
|
|||||||
types: [python]
|
types: [python]
|
||||||
require_serial: true
|
require_serial: true
|
||||||
files: ^homeassistant/.+\.py$
|
files: ^homeassistant/.+\.py$
|
||||||
|
- id: gen_requirements_all
|
||||||
|
name: gen_requirements_all
|
||||||
|
entry: script/run-in-env.sh python3 -m script.gen_requirements_all
|
||||||
|
pass_filenames: false
|
||||||
|
language: script
|
||||||
|
types: [json]
|
||||||
|
files: ^homeassistant/.+/manifest\.json$
|
||||||
|
- id: hassfest
|
||||||
|
name: hassfest
|
||||||
|
entry: script/run-in-env.sh python3 -m script.hassfest
|
||||||
|
pass_filenames: false
|
||||||
|
language: script
|
||||||
|
types: [json]
|
||||||
|
files: ^homeassistant/.+/manifest\.json$
|
||||||
|
27
CODEOWNERS
27
CODEOWNERS
@@ -17,6 +17,7 @@ homeassistant/components/abode/* @shred86
|
|||||||
homeassistant/components/adguard/* @frenck
|
homeassistant/components/adguard/* @frenck
|
||||||
homeassistant/components/airly/* @bieniu
|
homeassistant/components/airly/* @bieniu
|
||||||
homeassistant/components/airvisual/* @bachya
|
homeassistant/components/airvisual/* @bachya
|
||||||
|
homeassistant/components/alarmdecoder/* @ajschmidt8
|
||||||
homeassistant/components/alexa/* @home-assistant/cloud @ochlocracy
|
homeassistant/components/alexa/* @home-assistant/cloud @ochlocracy
|
||||||
homeassistant/components/almond/* @gcampax @balloob
|
homeassistant/components/almond/* @gcampax @balloob
|
||||||
homeassistant/components/alpha_vantage/* @fabaff
|
homeassistant/components/alpha_vantage/* @fabaff
|
||||||
@@ -51,6 +52,7 @@ homeassistant/components/beewi_smartclim/* @alemuro
|
|||||||
homeassistant/components/bitcoin/* @fabaff
|
homeassistant/components/bitcoin/* @fabaff
|
||||||
homeassistant/components/bizkaibus/* @UgaitzEtxebarria
|
homeassistant/components/bizkaibus/* @UgaitzEtxebarria
|
||||||
homeassistant/components/blink/* @fronzbot
|
homeassistant/components/blink/* @fronzbot
|
||||||
|
homeassistant/components/bmp280/* @belidzs
|
||||||
homeassistant/components/bmw_connected_drive/* @gerard33
|
homeassistant/components/bmw_connected_drive/* @gerard33
|
||||||
homeassistant/components/bom/* @maddenp
|
homeassistant/components/bom/* @maddenp
|
||||||
homeassistant/components/braviatv/* @robbiet480
|
homeassistant/components/braviatv/* @robbiet480
|
||||||
@@ -80,12 +82,13 @@ homeassistant/components/darksky/* @fabaff
|
|||||||
homeassistant/components/deconz/* @kane610
|
homeassistant/components/deconz/* @kane610
|
||||||
homeassistant/components/delijn/* @bollewolle
|
homeassistant/components/delijn/* @bollewolle
|
||||||
homeassistant/components/demo/* @home-assistant/core
|
homeassistant/components/demo/* @home-assistant/core
|
||||||
|
homeassistant/components/denonavr/* @scarface-4711 @starkillerOG
|
||||||
homeassistant/components/derivative/* @afaucogney
|
homeassistant/components/derivative/* @afaucogney
|
||||||
homeassistant/components/device_automation/* @home-assistant/core
|
homeassistant/components/device_automation/* @home-assistant/core
|
||||||
homeassistant/components/digital_ocean/* @fabaff
|
homeassistant/components/digital_ocean/* @fabaff
|
||||||
homeassistant/components/directv/* @ctalkington
|
homeassistant/components/directv/* @ctalkington
|
||||||
homeassistant/components/discogs/* @thibmaek
|
homeassistant/components/discogs/* @thibmaek
|
||||||
homeassistant/components/doorbird/* @oblogic7
|
homeassistant/components/doorbird/* @oblogic7 @bdraco
|
||||||
homeassistant/components/dsmr_reader/* @depl0y
|
homeassistant/components/dsmr_reader/* @depl0y
|
||||||
homeassistant/components/dweet/* @fabaff
|
homeassistant/components/dweet/* @fabaff
|
||||||
homeassistant/components/dynalite/* @ziv1234
|
homeassistant/components/dynalite/* @ziv1234
|
||||||
@@ -96,6 +99,7 @@ homeassistant/components/edl21/* @mtdcr
|
|||||||
homeassistant/components/egardia/* @jeroenterheerdt
|
homeassistant/components/egardia/* @jeroenterheerdt
|
||||||
homeassistant/components/eight_sleep/* @mezz64
|
homeassistant/components/eight_sleep/* @mezz64
|
||||||
homeassistant/components/elgato/* @frenck
|
homeassistant/components/elgato/* @frenck
|
||||||
|
homeassistant/components/elkm1/* @bdraco
|
||||||
homeassistant/components/elv/* @majuss
|
homeassistant/components/elv/* @majuss
|
||||||
homeassistant/components/emby/* @mezz64
|
homeassistant/components/emby/* @mezz64
|
||||||
homeassistant/components/emoncms/* @borpin
|
homeassistant/components/emoncms/* @borpin
|
||||||
@@ -122,7 +126,7 @@ homeassistant/components/fortigate/* @kifeo
|
|||||||
homeassistant/components/fortios/* @kimfrellsen
|
homeassistant/components/fortios/* @kimfrellsen
|
||||||
homeassistant/components/foscam/* @skgsergio
|
homeassistant/components/foscam/* @skgsergio
|
||||||
homeassistant/components/foursquare/* @robbiet480
|
homeassistant/components/foursquare/* @robbiet480
|
||||||
homeassistant/components/freebox/* @snoof85
|
homeassistant/components/freebox/* @snoof85 @Quentame
|
||||||
homeassistant/components/fronius/* @nielstron
|
homeassistant/components/fronius/* @nielstron
|
||||||
homeassistant/components/frontend/* @home-assistant/frontend
|
homeassistant/components/frontend/* @home-assistant/frontend
|
||||||
homeassistant/components/garmin_connect/* @cyberjunky
|
homeassistant/components/garmin_connect/* @cyberjunky
|
||||||
@@ -146,7 +150,7 @@ homeassistant/components/griddy/* @bdraco
|
|||||||
homeassistant/components/group/* @home-assistant/core
|
homeassistant/components/group/* @home-assistant/core
|
||||||
homeassistant/components/growatt_server/* @indykoning
|
homeassistant/components/growatt_server/* @indykoning
|
||||||
homeassistant/components/gtfs/* @robbiet480
|
homeassistant/components/gtfs/* @robbiet480
|
||||||
homeassistant/components/harmony/* @ehendrix23
|
homeassistant/components/harmony/* @ehendrix23 @bramkragten @bdraco
|
||||||
homeassistant/components/hassio/* @home-assistant/hass-io
|
homeassistant/components/hassio/* @home-assistant/hass-io
|
||||||
homeassistant/components/heatmiser/* @andylockran
|
homeassistant/components/heatmiser/* @andylockran
|
||||||
homeassistant/components/heos/* @andrewsayre
|
homeassistant/components/heos/* @andrewsayre
|
||||||
@@ -183,6 +187,7 @@ homeassistant/components/intesishome/* @jnimmo
|
|||||||
homeassistant/components/ios/* @robbiet480
|
homeassistant/components/ios/* @robbiet480
|
||||||
homeassistant/components/iperf3/* @rohankapoorcom
|
homeassistant/components/iperf3/* @rohankapoorcom
|
||||||
homeassistant/components/ipma/* @dgomes @abmantis
|
homeassistant/components/ipma/* @dgomes @abmantis
|
||||||
|
homeassistant/components/ipp/* @ctalkington
|
||||||
homeassistant/components/iqvia/* @bachya
|
homeassistant/components/iqvia/* @bachya
|
||||||
homeassistant/components/irish_rail_transport/* @ttroy50
|
homeassistant/components/irish_rail_transport/* @ttroy50
|
||||||
homeassistant/components/izone/* @Swamp-Ig
|
homeassistant/components/izone/* @Swamp-Ig
|
||||||
@@ -210,6 +215,7 @@ homeassistant/components/luci/* @fbradyirl @mzdrale
|
|||||||
homeassistant/components/luftdaten/* @fabaff
|
homeassistant/components/luftdaten/* @fabaff
|
||||||
homeassistant/components/lupusec/* @majuss
|
homeassistant/components/lupusec/* @majuss
|
||||||
homeassistant/components/lutron/* @JonGilmore
|
homeassistant/components/lutron/* @JonGilmore
|
||||||
|
homeassistant/components/lutron_caseta/* @swails
|
||||||
homeassistant/components/mastodon/* @fabaff
|
homeassistant/components/mastodon/* @fabaff
|
||||||
homeassistant/components/matrix/* @tinloaf
|
homeassistant/components/matrix/* @tinloaf
|
||||||
homeassistant/components/mcp23017/* @jardiamj
|
homeassistant/components/mcp23017/* @jardiamj
|
||||||
@@ -226,12 +232,13 @@ homeassistant/components/min_max/* @fabaff
|
|||||||
homeassistant/components/minecraft_server/* @elmurato
|
homeassistant/components/minecraft_server/* @elmurato
|
||||||
homeassistant/components/minio/* @tkislan
|
homeassistant/components/minio/* @tkislan
|
||||||
homeassistant/components/mobile_app/* @robbiet480
|
homeassistant/components/mobile_app/* @robbiet480
|
||||||
homeassistant/components/modbus/* @adamchengtkc
|
homeassistant/components/modbus/* @adamchengtkc @janiversen
|
||||||
homeassistant/components/monoprice/* @etsinko
|
homeassistant/components/monoprice/* @etsinko
|
||||||
homeassistant/components/moon/* @fabaff
|
homeassistant/components/moon/* @fabaff
|
||||||
homeassistant/components/mpd/* @fabaff
|
homeassistant/components/mpd/* @fabaff
|
||||||
homeassistant/components/mqtt/* @home-assistant/core
|
homeassistant/components/mqtt/* @home-assistant/core
|
||||||
homeassistant/components/msteams/* @peroyvind
|
homeassistant/components/msteams/* @peroyvind
|
||||||
|
homeassistant/components/myq/* @bdraco
|
||||||
homeassistant/components/mysensors/* @MartinHjelmare
|
homeassistant/components/mysensors/* @MartinHjelmare
|
||||||
homeassistant/components/mystrom/* @fabaff
|
homeassistant/components/mystrom/* @fabaff
|
||||||
homeassistant/components/neato/* @dshokouhi @Santobert
|
homeassistant/components/neato/* @dshokouhi @Santobert
|
||||||
@@ -241,7 +248,9 @@ homeassistant/components/ness_alarm/* @nickw444
|
|||||||
homeassistant/components/nest/* @awarecan
|
homeassistant/components/nest/* @awarecan
|
||||||
homeassistant/components/netatmo/* @cgtobi
|
homeassistant/components/netatmo/* @cgtobi
|
||||||
homeassistant/components/netdata/* @fabaff
|
homeassistant/components/netdata/* @fabaff
|
||||||
|
homeassistant/components/nexia/* @ryannazaretian @bdraco
|
||||||
homeassistant/components/nextbus/* @vividboarder
|
homeassistant/components/nextbus/* @vividboarder
|
||||||
|
homeassistant/components/nextcloud/* @meichthys
|
||||||
homeassistant/components/nilu/* @hfurubotten
|
homeassistant/components/nilu/* @hfurubotten
|
||||||
homeassistant/components/nissan_leaf/* @filcole
|
homeassistant/components/nissan_leaf/* @filcole
|
||||||
homeassistant/components/nmbs/* @thibmaek
|
homeassistant/components/nmbs/* @thibmaek
|
||||||
@@ -250,7 +259,9 @@ homeassistant/components/notify/* @home-assistant/core
|
|||||||
homeassistant/components/notion/* @bachya
|
homeassistant/components/notion/* @bachya
|
||||||
homeassistant/components/nsw_fuel_station/* @nickw444
|
homeassistant/components/nsw_fuel_station/* @nickw444
|
||||||
homeassistant/components/nsw_rural_fire_service_feed/* @exxamalte
|
homeassistant/components/nsw_rural_fire_service_feed/* @exxamalte
|
||||||
|
homeassistant/components/nuheat/* @bdraco
|
||||||
homeassistant/components/nuki/* @pvizeli
|
homeassistant/components/nuki/* @pvizeli
|
||||||
|
homeassistant/components/nut/* @bdraco
|
||||||
homeassistant/components/nws/* @MatthewFlamm
|
homeassistant/components/nws/* @MatthewFlamm
|
||||||
homeassistant/components/nzbget/* @chriscla
|
homeassistant/components/nzbget/* @chriscla
|
||||||
homeassistant/components/obihai/* @dshokouhi
|
homeassistant/components/obihai/* @dshokouhi
|
||||||
@@ -275,17 +286,21 @@ homeassistant/components/plaato/* @JohNan
|
|||||||
homeassistant/components/plant/* @ChristianKuehnel
|
homeassistant/components/plant/* @ChristianKuehnel
|
||||||
homeassistant/components/plex/* @jjlawren
|
homeassistant/components/plex/* @jjlawren
|
||||||
homeassistant/components/plugwise/* @laetificat @CoMPaTech @bouwew
|
homeassistant/components/plugwise/* @laetificat @CoMPaTech @bouwew
|
||||||
|
homeassistant/components/plum_lightpad/* @ColinHarrington
|
||||||
homeassistant/components/point/* @fredrike
|
homeassistant/components/point/* @fredrike
|
||||||
|
homeassistant/components/powerwall/* @bdraco
|
||||||
homeassistant/components/proxmoxve/* @k4ds3
|
homeassistant/components/proxmoxve/* @k4ds3
|
||||||
homeassistant/components/ps4/* @ktnrg45
|
homeassistant/components/ps4/* @ktnrg45
|
||||||
homeassistant/components/ptvsd/* @swamp-ig
|
homeassistant/components/ptvsd/* @swamp-ig
|
||||||
homeassistant/components/push/* @dgomes
|
homeassistant/components/push/* @dgomes
|
||||||
homeassistant/components/pvoutput/* @fabaff
|
homeassistant/components/pvoutput/* @fabaff
|
||||||
|
homeassistant/components/pvpc_hourly_pricing/* @azogue
|
||||||
homeassistant/components/qld_bushfire/* @exxamalte
|
homeassistant/components/qld_bushfire/* @exxamalte
|
||||||
homeassistant/components/qnap/* @colinodell
|
homeassistant/components/qnap/* @colinodell
|
||||||
homeassistant/components/quantum_gateway/* @cisasteelersfan
|
homeassistant/components/quantum_gateway/* @cisasteelersfan
|
||||||
homeassistant/components/qvr_pro/* @oblogic7
|
homeassistant/components/qvr_pro/* @oblogic7
|
||||||
homeassistant/components/qwikswitch/* @kellerza
|
homeassistant/components/qwikswitch/* @kellerza
|
||||||
|
homeassistant/components/rachio/* @bdraco
|
||||||
homeassistant/components/rainbird/* @konikvranik
|
homeassistant/components/rainbird/* @konikvranik
|
||||||
homeassistant/components/raincloud/* @vanstinator
|
homeassistant/components/raincloud/* @vanstinator
|
||||||
homeassistant/components/rainforest_eagle/* @gtdiehl @jcalbert
|
homeassistant/components/rainforest_eagle/* @gtdiehl @jcalbert
|
||||||
@@ -302,6 +317,7 @@ homeassistant/components/saj/* @fredericvl
|
|||||||
homeassistant/components/salt/* @bjornorri
|
homeassistant/components/salt/* @bjornorri
|
||||||
homeassistant/components/samsungtv/* @escoand
|
homeassistant/components/samsungtv/* @escoand
|
||||||
homeassistant/components/scene/* @home-assistant/core
|
homeassistant/components/scene/* @home-assistant/core
|
||||||
|
homeassistant/components/schluter/* @prairieapps
|
||||||
homeassistant/components/scrape/* @fabaff
|
homeassistant/components/scrape/* @fabaff
|
||||||
homeassistant/components/script/* @home-assistant/core
|
homeassistant/components/script/* @home-assistant/core
|
||||||
homeassistant/components/search/* @home-assistant/core
|
homeassistant/components/search/* @home-assistant/core
|
||||||
@@ -331,6 +347,7 @@ homeassistant/components/solax/* @squishykid
|
|||||||
homeassistant/components/soma/* @ratsept
|
homeassistant/components/soma/* @ratsept
|
||||||
homeassistant/components/somfy/* @tetienne
|
homeassistant/components/somfy/* @tetienne
|
||||||
homeassistant/components/songpal/* @rytilahti
|
homeassistant/components/songpal/* @rytilahti
|
||||||
|
homeassistant/components/sonos/* @amelchio
|
||||||
homeassistant/components/spaceapi/* @fabaff
|
homeassistant/components/spaceapi/* @fabaff
|
||||||
homeassistant/components/speedtestdotnet/* @rohankapoorcom
|
homeassistant/components/speedtestdotnet/* @rohankapoorcom
|
||||||
homeassistant/components/spider/* @peternijssen
|
homeassistant/components/spider/* @peternijssen
|
||||||
@@ -354,7 +371,7 @@ homeassistant/components/switchmate/* @danielhiversen
|
|||||||
homeassistant/components/syncthru/* @nielstron
|
homeassistant/components/syncthru/* @nielstron
|
||||||
homeassistant/components/synology_srm/* @aerialls
|
homeassistant/components/synology_srm/* @aerialls
|
||||||
homeassistant/components/syslog/* @fabaff
|
homeassistant/components/syslog/* @fabaff
|
||||||
homeassistant/components/tado/* @michaelarnauts
|
homeassistant/components/tado/* @michaelarnauts @bdraco
|
||||||
homeassistant/components/tahoma/* @philklei
|
homeassistant/components/tahoma/* @philklei
|
||||||
homeassistant/components/tankerkoenig/* @guillempages
|
homeassistant/components/tankerkoenig/* @guillempages
|
||||||
homeassistant/components/tautulli/* @ludeeus
|
homeassistant/components/tautulli/* @ludeeus
|
||||||
|
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ARG BUILD_FROM
|
||||||
|
FROM ${BUILD_FROM}
|
||||||
|
|
||||||
|
WORKDIR /usr/src
|
||||||
|
|
||||||
|
## Setup Home Assistant
|
||||||
|
COPY . homeassistant/
|
||||||
|
RUN pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
|
||||||
|
-r homeassistant/requirements_all.txt -c homeassistant/homeassistant/package_constraints.txt \
|
||||||
|
&& pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links "${WHEELS_LINKS}" \
|
||||||
|
-e ./homeassistant \
|
||||||
|
&& python3 -m compileall homeassistant/homeassistant
|
||||||
|
|
||||||
|
# Home Assistant S6-Overlay
|
||||||
|
COPY rootfs /
|
||||||
|
|
||||||
|
WORKDIR /config
|
@@ -14,7 +14,7 @@ schedules:
|
|||||||
always: true
|
always: true
|
||||||
variables:
|
variables:
|
||||||
- name: versionBuilder
|
- name: versionBuilder
|
||||||
value: '6.9'
|
value: '7.2.0'
|
||||||
- group: docker
|
- group: docker
|
||||||
- group: github
|
- group: github
|
||||||
- group: twine
|
- group: twine
|
||||||
@@ -108,11 +108,9 @@ stages:
|
|||||||
docker run --rm --privileged \
|
docker run --rm --privileged \
|
||||||
-v ~/.docker:/root/.docker:rw \
|
-v ~/.docker:/root/.docker:rw \
|
||||||
-v /run/docker.sock:/run/docker.sock:rw \
|
-v /run/docker.sock:/run/docker.sock:rw \
|
||||||
-v $(pwd):/homeassistant:ro \
|
-v $(pwd):/data:ro \
|
||||||
homeassistant/amd64-builder:$(versionBuilder) \
|
homeassistant/amd64-builder:$(versionBuilder) \
|
||||||
--homeassistant $(homeassistantRelease) "--$(buildArch)" \
|
--generic $(homeassistantRelease) "--$(buildArch)" -t /data \
|
||||||
-r https://github.com/home-assistant/hassio-homeassistant \
|
|
||||||
-t generic --docker-hub homeassistant
|
|
||||||
|
|
||||||
docker run --rm --privileged \
|
docker run --rm --privileged \
|
||||||
-v ~/.docker:/root/.docker \
|
-v ~/.docker:/root/.docker \
|
||||||
|
@@ -7,7 +7,7 @@ trigger:
|
|||||||
- dev
|
- dev
|
||||||
pr: none
|
pr: none
|
||||||
schedules:
|
schedules:
|
||||||
- cron: "30 0 * * *"
|
- cron: "0 0 * * *"
|
||||||
displayName: "translation update"
|
displayName: "translation update"
|
||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
|
@@ -5,6 +5,7 @@ trigger:
|
|||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
- dev
|
- dev
|
||||||
|
- rc
|
||||||
paths:
|
paths:
|
||||||
include:
|
include:
|
||||||
- requirements_all.txt
|
- requirements_all.txt
|
||||||
@@ -18,7 +19,7 @@ schedules:
|
|||||||
always: true
|
always: true
|
||||||
variables:
|
variables:
|
||||||
- name: versionWheels
|
- name: versionWheels
|
||||||
value: '1.4-3.7-alpine3.10'
|
value: '1.10.1-3.7-alpine3.11'
|
||||||
resources:
|
resources:
|
||||||
repositories:
|
repositories:
|
||||||
- repository: azure
|
- repository: azure
|
||||||
@@ -32,8 +33,10 @@ jobs:
|
|||||||
builderVersion: '$(versionWheels)'
|
builderVersion: '$(versionWheels)'
|
||||||
builderApk: 'build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev'
|
builderApk: 'build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev'
|
||||||
builderPip: 'Cython;numpy'
|
builderPip: 'Cython;numpy'
|
||||||
|
skipBinary: 'aiohttp'
|
||||||
wheelsRequirement: 'requirements_wheels.txt'
|
wheelsRequirement: 'requirements_wheels.txt'
|
||||||
wheelsRequirementDiff: 'requirements_diff.txt'
|
wheelsRequirementDiff: 'requirements_diff.txt'
|
||||||
|
wheelsConstraint: 'homeassistant/package_constraints.txt'
|
||||||
preBuild:
|
preBuild:
|
||||||
- script: |
|
- script: |
|
||||||
cp requirements_all.txt requirements_wheels.txt
|
cp requirements_all.txt requirements_wheels.txt
|
||||||
@@ -69,9 +72,5 @@ jobs:
|
|||||||
sed -i "s|# py_noaa|py_noaa|g" ${requirement_file}
|
sed -i "s|# py_noaa|py_noaa|g" ${requirement_file}
|
||||||
sed -i "s|# bme680|bme680|g" ${requirement_file}
|
sed -i "s|# bme680|bme680|g" ${requirement_file}
|
||||||
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
|
sed -i "s|# python-gammu|python-gammu|g" ${requirement_file}
|
||||||
|
|
||||||
if [[ "$(buildArch)" =~ arm ]]; then
|
|
||||||
sed -i "s|# VL53L1X|VL53L1X|g" ${requirement_file}
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
displayName: 'Prepare requirements files for Hass.io'
|
displayName: 'Prepare requirements files for Hass.io'
|
||||||
|
14
build.json
Normal file
14
build.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"image": "homeassistant/{arch}-homeassistant",
|
||||||
|
"build_from": {
|
||||||
|
"aarch64": "homeassistant/aarch64-homeassistant-base:7.1.0",
|
||||||
|
"armhf": "homeassistant/armhf-homeassistant-base:7.1.0",
|
||||||
|
"armv7": "homeassistant/armv7-homeassistant-base:7.1.0",
|
||||||
|
"amd64": "homeassistant/amd64-homeassistant-base:7.1.0",
|
||||||
|
"i386": "homeassistant/i386-homeassistant-base:7.1.0"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"io.hass.type": "core"
|
||||||
|
},
|
||||||
|
"version_tag": true
|
||||||
|
}
|
29
docs/source/api/auth.rst
Normal file
29
docs/source/api/auth.rst
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
:mod:`homeassistant.auth`
|
||||||
|
=========================
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.auth
|
||||||
|
:members:
|
||||||
|
|
||||||
|
homeassistant.auth.auth\_store
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.auth.auth_store
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.auth.const
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.auth.const
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.auth.models
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.auth.models
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
@@ -1,7 +1,7 @@
|
|||||||
.. _bootstrap_module:
|
.. _bootstrap_module:
|
||||||
|
|
||||||
:mod:`homeassistant.bootstrap`
|
:mod:`homeassistant.bootstrap`
|
||||||
-------------------------
|
------------------------------
|
||||||
|
|
||||||
.. automodule:: homeassistant.bootstrap
|
.. automodule:: homeassistant.bootstrap
|
||||||
:members:
|
:members:
|
||||||
|
170
docs/source/api/components.rst
Normal file
170
docs/source/api/components.rst
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
:mod:`homeassistant.components`
|
||||||
|
===============================
|
||||||
|
|
||||||
|
air\_quality
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.air_quality
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
alarm\_control\_panel
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.alarm_control_panel
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
binary\_sensor
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.binary_sensor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
camera
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.camera
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
calendar
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.calendar
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
climate
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.climate
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
conversation
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.conversation
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
cover
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.cover
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
device\_tracker
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.device_tracker
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
fan
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.fan
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
light
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.light
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
lock
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.lock
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
media\_player
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.media_player
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
notify
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.notify
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
remote
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.remote
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
switch
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.switch
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
sensor
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.sensor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
vacuum
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.vacuum
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
water\_heater
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.water_heater
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
weather
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.weather
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
webhook
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.components.webhook
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
7
docs/source/api/config_entries.rst
Normal file
7
docs/source/api/config_entries.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.. _config_entries_module:
|
||||||
|
|
||||||
|
:mod:`homeassistant.config_entries`
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.config_entries
|
||||||
|
:members:
|
@@ -4,35 +4,4 @@
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
.. automodule:: homeassistant.core
|
.. automodule:: homeassistant.core
|
||||||
|
:members:
|
||||||
.. autoclass:: Config
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: Event
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: EventBus
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: HomeAssistant
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: State
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: StateMachine
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: ServiceCall
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: ServiceRegistry
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Module contents
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.core
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
7
docs/source/api/data_entry_flow.rst
Normal file
7
docs/source/api/data_entry_flow.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.. _data_entry_flow_module:
|
||||||
|
|
||||||
|
:mod:`homeassistant.data_entry_flow`
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.data_entry_flow
|
||||||
|
:members:
|
@@ -1,10 +0,0 @@
|
|||||||
.. _components_device_tracker_module:
|
|
||||||
|
|
||||||
:mod:`homeassistant.components.device_tracker`
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.components.device_tracker
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: Device
|
|
||||||
:members:
|
|
@@ -1,12 +0,0 @@
|
|||||||
.. _helpers_entity_module:
|
|
||||||
|
|
||||||
:mod:`homeassistant.helpers.entity`
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity
|
|
||||||
|
|
||||||
.. autoclass:: Entity
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: ToggleEntity
|
|
||||||
:members:
|
|
@@ -1,20 +0,0 @@
|
|||||||
.. _helpers_event_module:
|
|
||||||
|
|
||||||
:mod:`homeassistant.helpers.event`
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.event
|
|
||||||
|
|
||||||
.. autofunction:: track_state_change
|
|
||||||
|
|
||||||
.. autofunction:: track_point_in_time
|
|
||||||
|
|
||||||
.. autofunction:: track_point_in_utc_time
|
|
||||||
|
|
||||||
.. autofunction:: track_sunrise
|
|
||||||
|
|
||||||
.. autofunction:: track_sunset
|
|
||||||
|
|
||||||
.. autofunction:: track_utc_time_change
|
|
||||||
|
|
||||||
.. autofunction:: track_time_change
|
|
7
docs/source/api/exceptions.rst
Normal file
7
docs/source/api/exceptions.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.. _exceptions_module:
|
||||||
|
|
||||||
|
:mod:`homeassistant.exceptions`
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.exceptions
|
||||||
|
:members:
|
@@ -1,287 +1,335 @@
|
|||||||
homeassistant.helpers package
|
:mod:`homeassistant.helpers`
|
||||||
=============================
|
============================
|
||||||
|
|
||||||
Submodules
|
|
||||||
----------
|
|
||||||
|
|
||||||
homeassistant.helpers.aiohttp_client module
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.aiohttp_client
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
homeassistant.helpers.area_registry module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.area_registry
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.condition module
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.condition
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.config_entry_flow module
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.config_entry_flow
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.config_validation module
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.config_validation
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.data_entry_flow module
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.data_entry_flow
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.deprecation module
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.deprecation
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.device_registry module
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.device_registry
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.discovery module
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.discovery
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.dispatcher module
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.dispatcher
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entity module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entity_component module
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity_component
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entity_platform module
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity_platform
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entity_registry module
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity_registry
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entity_values module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entity_values
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.entityfilter module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.entityfilter
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.event module
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.event
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.icon module
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.icon
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.intent module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.intent
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.json module
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.json
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.location module
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.location
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.logging module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.logging
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.restore_state module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.restore_state
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.script module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.script
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.service module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.service
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.signal module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.signal
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.state module
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.state
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.storage module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.storage
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.sun module
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.sun
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.system_info module
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.system_info
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.temperature module
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.temperature
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.template module
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.template
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.translation module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.translation
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.helpers.typing module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers.typing
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
Module contents
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.helpers
|
.. automodule:: homeassistant.helpers
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.aiohttp\_client
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.aiohttp_client
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.area\_registry
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.area_registry
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.check\_config
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.check_config
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.collection
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.collection
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.condition
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.condition
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.config\_entry\_flow
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.config_entry_flow
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.config\_entry\_oauth2\_flow
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.config_entry_oauth2_flow
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.config\_validation
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.config_validation
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.data\_entry\_flow
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.data_entry_flow
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.debounce
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.debounce
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.deprecation
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.deprecation
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.device\_registry
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.device_registry
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.discovery
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.discovery
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.dispatcher
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.dispatcher
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entity
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entity
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entity\_component
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entity_component
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entity\_platform
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entity_platform
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entity\_registry
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entity_registry
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entity\_values
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entity_values
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.entityfilter
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.entityfilter
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.event
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.event
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.icon
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.icon
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.integration\_platform
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.integration_platform
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.intent
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.intent
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.json
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.json
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.location
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.location
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.logging
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.logging
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.network
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.network
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.restore\_state
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.restore_state
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.script
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.script
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.service
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.service
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.signal
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.signal
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.state
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.state
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.storage
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.storage
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.sun
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.sun
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.system\_info
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.system_info
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.temperature
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.temperature
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.template
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.template
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.translation
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.translation
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.typing
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.typing
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.helpers.update\_coordinator
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.helpers.update_coordinator
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
@@ -1,70 +0,0 @@
|
|||||||
homeassistant package
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Subpackages
|
|
||||||
-----------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
helpers
|
|
||||||
util
|
|
||||||
|
|
||||||
Submodules
|
|
||||||
----------
|
|
||||||
|
|
||||||
bootstrap module
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.bootstrap
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
config module
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.config
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
const module
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.const
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
core module
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.core
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
exceptions module
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.exceptions
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
loader module
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.loader
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
Module contents
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
7
docs/source/api/loader.rst
Normal file
7
docs/source/api/loader.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.. _loader_module:
|
||||||
|
|
||||||
|
:mod:`homeassistant.loader`
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.loader
|
||||||
|
:members:
|
@@ -1,86 +1,159 @@
|
|||||||
homeassistant.util package
|
:mod:`homeassistant.util`
|
||||||
==========================
|
=========================
|
||||||
|
|
||||||
Submodules
|
|
||||||
----------
|
|
||||||
|
|
||||||
homeassistant.util.async_ module
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.async_
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.color module
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.color
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.distance module
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.distance
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.dt module
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.dt
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.location module
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.location
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.package module
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.package
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.temperature module
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.temperature
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.unit_system module
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.unit_system
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
homeassistant.util.yaml module
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util.yaml
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
Module contents
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. automodule:: homeassistant.util
|
.. automodule:: homeassistant.util
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.yaml
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.yaml
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.aiohttp
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.aiohttp
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.async\_
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.async_
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.color
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.color
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.decorator
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.decorator
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.distance
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.distance
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.dt
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.dt
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.json
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.json
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.location
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.location
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.logging
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.logging
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.network
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.network
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.package
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.package
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.pil
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.pil
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.pressure
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.pressure
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.ruamel\_yaml
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.ruamel_yaml
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.ssl
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.ssl
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.temperature
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.temperature
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.unit\_system
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.unit_system
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
homeassistant.util.volume
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: homeassistant.util.volume
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
@@ -26,7 +26,7 @@ from homeassistant.const import __short_version__, __version__
|
|||||||
PROJECT_NAME = 'Home Assistant'
|
PROJECT_NAME = 'Home Assistant'
|
||||||
PROJECT_PACKAGE_NAME = 'homeassistant'
|
PROJECT_PACKAGE_NAME = 'homeassistant'
|
||||||
PROJECT_AUTHOR = 'The Home Assistant Authors'
|
PROJECT_AUTHOR = 'The Home Assistant Authors'
|
||||||
PROJECT_COPYRIGHT = ' 2013-2018, {}'.format(PROJECT_AUTHOR)
|
PROJECT_COPYRIGHT = ' 2013-2020, {}'.format(PROJECT_AUTHOR)
|
||||||
PROJECT_LONG_DESCRIPTION = ('Home Assistant is an open-source '
|
PROJECT_LONG_DESCRIPTION = ('Home Assistant is an open-source '
|
||||||
'home automation platform running on Python 3. '
|
'home automation platform running on Python 3. '
|
||||||
'Track and control all devices at home and '
|
'Track and control all devices at home and '
|
||||||
|
@@ -339,7 +339,7 @@ def main() -> int:
|
|||||||
if args.pid_file:
|
if args.pid_file:
|
||||||
write_pid(args.pid_file)
|
write_pid(args.pid_file)
|
||||||
|
|
||||||
exit_code = asyncio.run(setup_and_run_hass(config_dir, args))
|
exit_code = asyncio.run(setup_and_run_hass(config_dir, args), debug=args.debug)
|
||||||
if exit_code == RESTART_EXIT_CODE and not args.runner:
|
if exit_code == RESTART_EXIT_CODE and not args.runner:
|
||||||
try_to_restart()
|
try_to_restart()
|
||||||
|
|
||||||
|
@@ -215,12 +215,14 @@ class AuthManager:
|
|||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
async def async_create_user(self, name: str) -> models.User:
|
async def async_create_user(
|
||||||
|
self, name: str, group_ids: Optional[List[str]] = None
|
||||||
|
) -> models.User:
|
||||||
"""Create a user."""
|
"""Create a user."""
|
||||||
kwargs: Dict[str, Any] = {
|
kwargs: Dict[str, Any] = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"is_active": True,
|
"is_active": True,
|
||||||
"group_ids": [GROUP_ID_ADMIN],
|
"group_ids": group_ids or [],
|
||||||
}
|
}
|
||||||
|
|
||||||
if await self._user_should_be_owner():
|
if await self._user_should_be_owner():
|
||||||
|
@@ -123,4 +123,8 @@ class Credentials:
|
|||||||
is_new = attr.ib(type=bool, default=True)
|
is_new = attr.ib(type=bool, default=True)
|
||||||
|
|
||||||
|
|
||||||
UserMeta = NamedTuple("UserMeta", [("name", Optional[str]), ("is_active", bool)])
|
class UserMeta(NamedTuple):
|
||||||
|
"""User metadata."""
|
||||||
|
|
||||||
|
name: Optional[str]
|
||||||
|
is_active: bool
|
||||||
|
@@ -20,6 +20,7 @@ from homeassistant.const import (
|
|||||||
REQUIRED_NEXT_PYTHON_VER,
|
REQUIRED_NEXT_PYTHON_VER,
|
||||||
)
|
)
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.setup import DATA_SETUP, async_setup_component
|
from homeassistant.setup import DATA_SETUP, async_setup_component
|
||||||
from homeassistant.util.logging import AsyncHandler
|
from homeassistant.util.logging import AsyncHandler
|
||||||
from homeassistant.util.package import async_get_user_site, is_virtual_env
|
from homeassistant.util.package import async_get_user_site, is_virtual_env
|
||||||
@@ -133,7 +134,7 @@ async def async_setup_hass(
|
|||||||
|
|
||||||
|
|
||||||
async def async_from_config_dict(
|
async def async_from_config_dict(
|
||||||
config: Dict[str, Any], hass: core.HomeAssistant
|
config: ConfigType, hass: core.HomeAssistant
|
||||||
) -> Optional[core.HomeAssistant]:
|
) -> Optional[core.HomeAssistant]:
|
||||||
"""Try to configure Home Assistant from a configuration dictionary.
|
"""Try to configure Home Assistant from a configuration dictionary.
|
||||||
|
|
||||||
@@ -324,15 +325,30 @@ async def _async_set_up_integrations(
|
|||||||
hass: core.HomeAssistant, config: Dict[str, Any]
|
hass: core.HomeAssistant, config: Dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up all the integrations."""
|
"""Set up all the integrations."""
|
||||||
|
|
||||||
|
async def async_setup_multi_components(domains: Set[str]) -> None:
|
||||||
|
"""Set up multiple domains. Log on failure."""
|
||||||
|
futures = {
|
||||||
|
domain: hass.async_create_task(async_setup_component(hass, domain, config))
|
||||||
|
for domain in domains
|
||||||
|
}
|
||||||
|
await asyncio.wait(futures.values())
|
||||||
|
errors = [domain for domain in domains if futures[domain].exception()]
|
||||||
|
for domain in errors:
|
||||||
|
exception = futures[domain].exception()
|
||||||
|
_LOGGER.error(
|
||||||
|
"Error setting up integration %s - received exception",
|
||||||
|
domain,
|
||||||
|
exc_info=(type(exception), exception, exception.__traceback__),
|
||||||
|
)
|
||||||
|
|
||||||
domains = _get_domains(hass, config)
|
domains = _get_domains(hass, config)
|
||||||
|
|
||||||
# Start up debuggers. Start these first in case they want to wait.
|
# Start up debuggers. Start these first in case they want to wait.
|
||||||
debuggers = domains & DEBUGGER_INTEGRATIONS
|
debuggers = domains & DEBUGGER_INTEGRATIONS
|
||||||
if debuggers:
|
if debuggers:
|
||||||
_LOGGER.debug("Starting up debuggers %s", debuggers)
|
_LOGGER.debug("Starting up debuggers %s", debuggers)
|
||||||
await asyncio.gather(
|
await async_setup_multi_components(debuggers)
|
||||||
*(async_setup_component(hass, domain, config) for domain in debuggers)
|
|
||||||
)
|
|
||||||
domains -= DEBUGGER_INTEGRATIONS
|
domains -= DEBUGGER_INTEGRATIONS
|
||||||
|
|
||||||
# Resolve all dependencies of all components so we can find the logging
|
# Resolve all dependencies of all components so we can find the logging
|
||||||
@@ -357,9 +373,7 @@ async def _async_set_up_integrations(
|
|||||||
if logging_domains:
|
if logging_domains:
|
||||||
_LOGGER.info("Setting up %s", logging_domains)
|
_LOGGER.info("Setting up %s", logging_domains)
|
||||||
|
|
||||||
await asyncio.gather(
|
await async_setup_multi_components(logging_domains)
|
||||||
*(async_setup_component(hass, domain, config) for domain in logging_domains)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Kick off loading the registries. They don't need to be awaited.
|
# Kick off loading the registries. They don't need to be awaited.
|
||||||
asyncio.gather(
|
asyncio.gather(
|
||||||
@@ -369,9 +383,7 @@ async def _async_set_up_integrations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if stage_1_domains:
|
if stage_1_domains:
|
||||||
await asyncio.gather(
|
await async_setup_multi_components(stage_1_domains)
|
||||||
*(async_setup_component(hass, domain, config) for domain in stage_1_domains)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Load all integrations
|
# Load all integrations
|
||||||
after_dependencies: Dict[str, Set[str]] = {}
|
after_dependencies: Dict[str, Set[str]] = {}
|
||||||
@@ -400,9 +412,7 @@ async def _async_set_up_integrations(
|
|||||||
|
|
||||||
_LOGGER.debug("Setting up %s", domains_to_load)
|
_LOGGER.debug("Setting up %s", domains_to_load)
|
||||||
|
|
||||||
await asyncio.gather(
|
await async_setup_multi_components(domains_to_load)
|
||||||
*(async_setup_component(hass, domain, config) for domain in domains_to_load)
|
|
||||||
)
|
|
||||||
|
|
||||||
last_load = domains_to_load
|
last_load = domains_to_load
|
||||||
stage_2_domains -= domains_to_load
|
stage_2_domains -= domains_to_load
|
||||||
@@ -412,9 +422,7 @@ async def _async_set_up_integrations(
|
|||||||
if stage_2_domains:
|
if stage_2_domains:
|
||||||
_LOGGER.debug("Final set up: %s", stage_2_domains)
|
_LOGGER.debug("Final set up: %s", stage_2_domains)
|
||||||
|
|
||||||
await asyncio.gather(
|
await async_setup_multi_components(stage_2_domains)
|
||||||
*(async_setup_component(hass, domain, config) for domain in stage_2_domains)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Wrap up startup
|
# Wrap up startup
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@@ -17,6 +17,6 @@
|
|||||||
"title": "Fyll ut innloggingsinformasjonen for Abode"
|
"title": "Fyll ut innloggingsinformasjonen for Abode"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Abode"
|
"title": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -263,7 +263,6 @@ def setup_abode_events(hass):
|
|||||||
TIMELINE.TEST_GROUP,
|
TIMELINE.TEST_GROUP,
|
||||||
TIMELINE.CAPTURE_GROUP,
|
TIMELINE.CAPTURE_GROUP,
|
||||||
TIMELINE.DEVICE_GROUP,
|
TIMELINE.DEVICE_GROUP,
|
||||||
TIMELINE.AUTOMATION_EDIT_GROUP,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
@@ -343,21 +342,14 @@ class AbodeDevice(Entity):
|
|||||||
class AbodeAutomation(Entity):
|
class AbodeAutomation(Entity):
|
||||||
"""Representation of an Abode automation."""
|
"""Representation of an Abode automation."""
|
||||||
|
|
||||||
def __init__(self, data, automation, event=None):
|
def __init__(self, data, automation):
|
||||||
"""Initialize for Abode automation."""
|
"""Initialize for Abode automation."""
|
||||||
self._data = data
|
self._data = data
|
||||||
self._automation = automation
|
self._automation = automation
|
||||||
self._event = event
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Subscribe to a group of Abode timeline events."""
|
"""Set up automation entity."""
|
||||||
if self._event:
|
self.hass.data[DOMAIN].entity_ids.add(self.entity_id)
|
||||||
self.hass.async_add_job(
|
|
||||||
self._data.abode.events.add_event_callback,
|
|
||||||
self._event,
|
|
||||||
self._update_callback,
|
|
||||||
)
|
|
||||||
self.hass.data[DOMAIN].entity_ids.add(self.entity_id)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
@@ -385,8 +377,3 @@ class AbodeAutomation(Entity):
|
|||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique ID to use for this automation."""
|
"""Return a unique ID to use for this automation."""
|
||||||
return self._automation.automation_id
|
return self._automation.automation_id
|
||||||
|
|
||||||
def _update_callback(self, device):
|
|
||||||
"""Update the automation state."""
|
|
||||||
self._automation.refresh()
|
|
||||||
self.schedule_update_ha_state()
|
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
"""Support for Abode Security System binary sensors."""
|
"""Support for Abode Security System binary sensors."""
|
||||||
import abodepy.helpers.constants as CONST
|
import abodepy.helpers.constants as CONST
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
from homeassistant.components.binary_sensor import (
|
||||||
|
DEVICE_CLASS_WINDOW,
|
||||||
|
BinarySensorDevice,
|
||||||
|
)
|
||||||
|
|
||||||
from . import AbodeDevice
|
from . import AbodeDevice
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
@@ -38,4 +41,6 @@ class AbodeBinarySensor(AbodeDevice, BinarySensorDevice):
|
|||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the class of the binary sensor."""
|
"""Return the class of the binary sensor."""
|
||||||
|
if self._device.get_value("is_window") == "1":
|
||||||
|
return DEVICE_CLASS_WINDOW
|
||||||
return self._device.generic_type
|
return self._device.generic_type
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
"""Support for Abode Security System switches."""
|
"""Support for Abode Security System switches."""
|
||||||
import abodepy.helpers.constants as CONST
|
import abodepy.helpers.constants as CONST
|
||||||
import abodepy.helpers.timeline as TIMELINE
|
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchDevice
|
from homeassistant.components.switch import SwitchDevice
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
@@ -24,9 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
entities.append(AbodeSwitch(data, device))
|
entities.append(AbodeSwitch(data, device))
|
||||||
|
|
||||||
for automation in data.abode.get_automations():
|
for automation in data.abode.get_automations():
|
||||||
entities.append(
|
entities.append(AbodeAutomationSwitch(data, automation))
|
||||||
AbodeAutomationSwitch(data, automation, TIMELINE.AUTOMATION_EDIT_GROUP)
|
|
||||||
)
|
|
||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
@@ -52,7 +49,7 @@ class AbodeAutomationSwitch(AbodeAutomation, SwitchDevice):
|
|||||||
"""A switch implementation for Abode automations."""
|
"""A switch implementation for Abode automations."""
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Subscribe Abode events."""
|
"""Set up trigger automation service."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
signal = f"abode_trigger_automation_{self.entity_id}"
|
signal = f"abode_trigger_automation_{self.entity_id}"
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"host": "Vert",
|
"host": "Vert",
|
||||||
"password": "Passord",
|
"password": "Passord",
|
||||||
"port": "Port",
|
"port": "",
|
||||||
"ssl": "AdGuard Hjem bruker et SSL-sertifikat",
|
"ssl": "AdGuard Hjem bruker et SSL-sertifikat",
|
||||||
"username": "Brukernavn",
|
"username": "Brukernavn",
|
||||||
"verify_ssl": "AdGuard Home bruker et riktig sertifikat"
|
"verify_ssl": "AdGuard Home bruker et riktig sertifikat"
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"name": "AdGuard Home",
|
"name": "AdGuard Home",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/adguard",
|
"documentation": "https://www.home-assistant.io/integrations/adguard",
|
||||||
"requirements": ["adguardhome==0.4.1"],
|
"requirements": ["adguardhome==0.4.2"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@frenck"]
|
"codeowners": ["@frenck"]
|
||||||
}
|
}
|
||||||
|
@@ -17,9 +17,9 @@
|
|||||||
"name": "Navn p\u00e5 integrasjonen"
|
"name": "Navn p\u00e5 integrasjonen"
|
||||||
},
|
},
|
||||||
"description": "Sett opp Airly luftkvalitet integrering. For \u00e5 generere API-n\u00f8kkel g\u00e5 til https://developer.airly.eu/register",
|
"description": "Sett opp Airly luftkvalitet integrering. For \u00e5 generere API-n\u00f8kkel g\u00e5 til https://developer.airly.eu/register",
|
||||||
"title": "Airly"
|
"title": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Airly"
|
"title": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,6 +2,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
from aiohttp.client_exceptions import ClientConnectorError
|
from aiohttp.client_exceptions import ClientConnectorError
|
||||||
from airly import Airly
|
from airly import Airly
|
||||||
@@ -10,28 +11,40 @@ import async_timeout
|
|||||||
|
|
||||||
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 Config, HomeAssistant
|
from homeassistant.core import Config, HomeAssistant
|
||||||
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_API_ADVICE,
|
ATTR_API_ADVICE,
|
||||||
ATTR_API_CAQI,
|
ATTR_API_CAQI,
|
||||||
ATTR_API_CAQI_DESCRIPTION,
|
ATTR_API_CAQI_DESCRIPTION,
|
||||||
ATTR_API_CAQI_LEVEL,
|
ATTR_API_CAQI_LEVEL,
|
||||||
DATA_CLIENT,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
MAX_REQUESTS_PER_DAY,
|
||||||
NO_AIRLY_SENSORS,
|
NO_AIRLY_SENSORS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PLATFORMS = ["air_quality", "sensor"]
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEFAULT_SCAN_INTERVAL = timedelta(minutes=10)
|
|
||||||
|
def set_update_interval(hass, instances):
|
||||||
|
"""Set update_interval to another configured Airly instances."""
|
||||||
|
# We check how many Airly configured instances are and calculate interval to not
|
||||||
|
# exceed allowed numbers of requests.
|
||||||
|
interval = timedelta(minutes=ceil(24 * 60 / MAX_REQUESTS_PER_DAY) * instances)
|
||||||
|
|
||||||
|
if hass.data.get(DOMAIN):
|
||||||
|
for instance in hass.data[DOMAIN].values():
|
||||||
|
instance.update_interval = interval
|
||||||
|
|
||||||
|
return interval
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: Config) -> bool:
|
async def async_setup(hass: HomeAssistant, config: Config) -> bool:
|
||||||
"""Set up configured Airly."""
|
"""Set up configured Airly."""
|
||||||
hass.data[DOMAIN] = {}
|
|
||||||
hass.data[DOMAIN][DATA_CLIENT] = {}
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -48,70 +61,85 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
)
|
)
|
||||||
|
|
||||||
websession = async_get_clientsession(hass)
|
websession = async_get_clientsession(hass)
|
||||||
|
# Change update_interval for other Airly instances
|
||||||
airly = AirlyData(websession, api_key, latitude, longitude)
|
update_interval = set_update_interval(
|
||||||
|
hass, len(hass.config_entries.async_entries(DOMAIN))
|
||||||
await airly.async_update()
|
|
||||||
|
|
||||||
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = airly
|
|
||||||
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.async_forward_entry_setup(config_entry, "air_quality")
|
|
||||||
)
|
)
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
|
coordinator = AirlyDataUpdateCoordinator(
|
||||||
|
hass, websession, api_key, latitude, longitude, update_interval
|
||||||
)
|
)
|
||||||
|
await coordinator.async_refresh()
|
||||||
|
|
||||||
|
if not coordinator.last_update_success:
|
||||||
|
raise ConfigEntryNotReady
|
||||||
|
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
hass.data[DOMAIN][config_entry.entry_id] = coordinator
|
||||||
|
|
||||||
|
for component in PLATFORMS:
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.async_forward_entry_setup(config_entry, component)
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass, config_entry):
|
async def async_unload_entry(hass, config_entry):
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)
|
unload_ok = all(
|
||||||
await hass.config_entries.async_forward_entry_unload(config_entry, "air_quality")
|
await asyncio.gather(
|
||||||
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
|
*[
|
||||||
return True
|
hass.config_entries.async_forward_entry_unload(config_entry, component)
|
||||||
|
for component in PLATFORMS
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if unload_ok:
|
||||||
|
hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||||
|
|
||||||
|
# Change update_interval for other Airly instances
|
||||||
|
set_update_interval(hass, len(hass.data[DOMAIN]))
|
||||||
|
|
||||||
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
class AirlyData:
|
class AirlyDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
"""Define an object to hold Airly data."""
|
"""Define an object to hold Airly data."""
|
||||||
|
|
||||||
def __init__(self, session, api_key, latitude, longitude):
|
def __init__(self, hass, session, api_key, latitude, longitude, update_interval):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
self.longitude = longitude
|
self.longitude = longitude
|
||||||
self.airly = Airly(api_key, session)
|
self.airly = Airly(api_key, session)
|
||||||
self.data = {}
|
|
||||||
|
|
||||||
@Throttle(DEFAULT_SCAN_INTERVAL)
|
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
|
||||||
async def async_update(self):
|
|
||||||
"""Update Airly data."""
|
|
||||||
|
|
||||||
try:
|
async def _async_update_data(self):
|
||||||
with async_timeout.timeout(20):
|
"""Update data via library."""
|
||||||
measurements = self.airly.create_measurements_session_point(
|
data = {}
|
||||||
self.latitude, self.longitude
|
with async_timeout.timeout(20):
|
||||||
)
|
measurements = self.airly.create_measurements_session_point(
|
||||||
|
self.latitude, self.longitude
|
||||||
|
)
|
||||||
|
try:
|
||||||
await measurements.update()
|
await measurements.update()
|
||||||
|
except (AirlyError, ClientConnectorError) as error:
|
||||||
|
raise UpdateFailed(error)
|
||||||
|
|
||||||
values = measurements.current["values"]
|
values = measurements.current["values"]
|
||||||
index = measurements.current["indexes"][0]
|
index = measurements.current["indexes"][0]
|
||||||
standards = measurements.current["standards"]
|
standards = measurements.current["standards"]
|
||||||
|
|
||||||
if index["description"] == NO_AIRLY_SENSORS:
|
if index["description"] == NO_AIRLY_SENSORS:
|
||||||
_LOGGER.error("Can't retrieve data: no Airly sensors in this area")
|
raise UpdateFailed("Can't retrieve data: no Airly sensors in this area")
|
||||||
return
|
for value in values:
|
||||||
for value in values:
|
data[value["name"]] = value["value"]
|
||||||
self.data[value["name"]] = value["value"]
|
for standard in standards:
|
||||||
for standard in standards:
|
data[f"{standard['pollutant']}_LIMIT"] = standard["limit"]
|
||||||
self.data[f"{standard['pollutant']}_LIMIT"] = standard["limit"]
|
data[f"{standard['pollutant']}_PERCENT"] = standard["percent"]
|
||||||
self.data[f"{standard['pollutant']}_PERCENT"] = standard["percent"]
|
data[ATTR_API_CAQI] = index["value"]
|
||||||
self.data[ATTR_API_CAQI] = index["value"]
|
data[ATTR_API_CAQI_LEVEL] = index["level"].lower().replace("_", " ")
|
||||||
self.data[ATTR_API_CAQI_LEVEL] = index["level"].lower().replace("_", " ")
|
data[ATTR_API_CAQI_DESCRIPTION] = index["description"]
|
||||||
self.data[ATTR_API_CAQI_DESCRIPTION] = index["description"]
|
data[ATTR_API_ADVICE] = index["advice"]
|
||||||
self.data[ATTR_API_ADVICE] = index["advice"]
|
return data
|
||||||
_LOGGER.debug("Data retrieved from Airly")
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
_LOGGER.error("Asyncio Timeout Error")
|
|
||||||
except (ValueError, AirlyError, ClientConnectorError) as error:
|
|
||||||
_LOGGER.error(error)
|
|
||||||
self.data = {}
|
|
||||||
|
@@ -18,13 +18,13 @@ from .const import (
|
|||||||
ATTR_API_PM25,
|
ATTR_API_PM25,
|
||||||
ATTR_API_PM25_LIMIT,
|
ATTR_API_PM25_LIMIT,
|
||||||
ATTR_API_PM25_PERCENT,
|
ATTR_API_PM25_PERCENT,
|
||||||
DATA_CLIENT,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTION = "Data provided by Airly"
|
ATTRIBUTION = "Data provided by Airly"
|
||||||
|
|
||||||
LABEL_ADVICE = "advice"
|
LABEL_ADVICE = "advice"
|
||||||
|
LABEL_AQI_DESCRIPTION = f"{ATTR_AQI}_description"
|
||||||
LABEL_AQI_LEVEL = f"{ATTR_AQI}_level"
|
LABEL_AQI_LEVEL = f"{ATTR_AQI}_level"
|
||||||
LABEL_PM_2_5_LIMIT = f"{ATTR_PM_2_5}_limit"
|
LABEL_PM_2_5_LIMIT = f"{ATTR_PM_2_5}_limit"
|
||||||
LABEL_PM_2_5_PERCENT = f"{ATTR_PM_2_5}_percent_of_limit"
|
LABEL_PM_2_5_PERCENT = f"{ATTR_PM_2_5}_percent_of_limit"
|
||||||
@@ -36,9 +36,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
"""Set up Airly air_quality entity based on a config entry."""
|
"""Set up Airly air_quality entity based on a config entry."""
|
||||||
name = config_entry.data[CONF_NAME]
|
name = config_entry.data[CONF_NAME]
|
||||||
|
|
||||||
data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
async_add_entities([AirlyAirQuality(data, name, config_entry.unique_id)], True)
|
async_add_entities(
|
||||||
|
[AirlyAirQuality(coordinator, name, config_entry.unique_id)], False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def round_state(func):
|
def round_state(func):
|
||||||
@@ -56,23 +58,23 @@ def round_state(func):
|
|||||||
class AirlyAirQuality(AirQualityEntity):
|
class AirlyAirQuality(AirQualityEntity):
|
||||||
"""Define an Airly air quality."""
|
"""Define an Airly air quality."""
|
||||||
|
|
||||||
def __init__(self, airly, name, unique_id):
|
def __init__(self, coordinator, name, unique_id):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self.airly = airly
|
self.coordinator = coordinator
|
||||||
self.data = airly.data
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._unique_id = unique_id
|
self._unique_id = unique_id
|
||||||
self._pm_2_5 = None
|
|
||||||
self._pm_10 = None
|
|
||||||
self._aqi = None
|
|
||||||
self._icon = "mdi:blur"
|
self._icon = "mdi:blur"
|
||||||
self._attrs = {}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name."""
|
"""Return the name."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Return the polling requirement of the entity."""
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
"""Return the icon."""
|
"""Return the icon."""
|
||||||
@@ -82,30 +84,25 @@ class AirlyAirQuality(AirQualityEntity):
|
|||||||
@round_state
|
@round_state
|
||||||
def air_quality_index(self):
|
def air_quality_index(self):
|
||||||
"""Return the air quality index."""
|
"""Return the air quality index."""
|
||||||
return self._aqi
|
return self.coordinator.data[ATTR_API_CAQI]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@round_state
|
@round_state
|
||||||
def particulate_matter_2_5(self):
|
def particulate_matter_2_5(self):
|
||||||
"""Return the particulate matter 2.5 level."""
|
"""Return the particulate matter 2.5 level."""
|
||||||
return self._pm_2_5
|
return self.coordinator.data[ATTR_API_PM25]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@round_state
|
@round_state
|
||||||
def particulate_matter_10(self):
|
def particulate_matter_10(self):
|
||||||
"""Return the particulate matter 10 level."""
|
"""Return the particulate matter 10 level."""
|
||||||
return self._pm_10
|
return self.coordinator.data[ATTR_API_PM10]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attribution(self):
|
def attribution(self):
|
||||||
"""Return the attribution."""
|
"""Return the attribution."""
|
||||||
return ATTRIBUTION
|
return ATTRIBUTION
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
"""Return the CAQI description."""
|
|
||||||
return self.data[ATTR_API_CAQI_DESCRIPTION]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique_id for this entity."""
|
"""Return a unique_id for this entity."""
|
||||||
@@ -114,25 +111,29 @@ class AirlyAirQuality(AirQualityEntity):
|
|||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return bool(self.data)
|
return self.coordinator.last_update_success
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
self._attrs[LABEL_ADVICE] = self.data[ATTR_API_ADVICE]
|
return {
|
||||||
self._attrs[LABEL_AQI_LEVEL] = self.data[ATTR_API_CAQI_LEVEL]
|
LABEL_AQI_DESCRIPTION: self.coordinator.data[ATTR_API_CAQI_DESCRIPTION],
|
||||||
self._attrs[LABEL_PM_2_5_LIMIT] = self.data[ATTR_API_PM25_LIMIT]
|
LABEL_ADVICE: self.coordinator.data[ATTR_API_ADVICE],
|
||||||
self._attrs[LABEL_PM_2_5_PERCENT] = round(self.data[ATTR_API_PM25_PERCENT])
|
LABEL_AQI_LEVEL: self.coordinator.data[ATTR_API_CAQI_LEVEL],
|
||||||
self._attrs[LABEL_PM_10_LIMIT] = self.data[ATTR_API_PM10_LIMIT]
|
LABEL_PM_2_5_LIMIT: self.coordinator.data[ATTR_API_PM25_LIMIT],
|
||||||
self._attrs[LABEL_PM_10_PERCENT] = round(self.data[ATTR_API_PM10_PERCENT])
|
LABEL_PM_2_5_PERCENT: round(self.coordinator.data[ATTR_API_PM25_PERCENT]),
|
||||||
return self._attrs
|
LABEL_PM_10_LIMIT: self.coordinator.data[ATTR_API_PM10_LIMIT],
|
||||||
|
LABEL_PM_10_PERCENT: round(self.coordinator.data[ATTR_API_PM10_PERCENT]),
|
||||||
|
}
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Connect to dispatcher listening for entity data notifications."""
|
||||||
|
self.coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""Disconnect from update signal."""
|
||||||
|
self.coordinator.async_remove_listener(self.async_write_ha_state)
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the entity."""
|
"""Update Airly entity."""
|
||||||
await self.airly.async_update()
|
await self.coordinator.async_request_refresh()
|
||||||
|
|
||||||
if self.airly.data:
|
|
||||||
self.data = self.airly.data
|
|
||||||
self._pm_10 = self.data[ATTR_API_PM10]
|
|
||||||
self._pm_2_5 = self.data[ATTR_API_PM25]
|
|
||||||
self._aqi = self.data[ATTR_API_CAQI]
|
|
||||||
|
@@ -13,7 +13,7 @@ ATTR_API_PM25_LIMIT = "PM25_LIMIT"
|
|||||||
ATTR_API_PM25_PERCENT = "PM25_PERCENT"
|
ATTR_API_PM25_PERCENT = "PM25_PERCENT"
|
||||||
ATTR_API_PRESSURE = "PRESSURE"
|
ATTR_API_PRESSURE = "PRESSURE"
|
||||||
ATTR_API_TEMPERATURE = "TEMPERATURE"
|
ATTR_API_TEMPERATURE = "TEMPERATURE"
|
||||||
DATA_CLIENT = "client"
|
|
||||||
DEFAULT_NAME = "Airly"
|
DEFAULT_NAME = "Airly"
|
||||||
DOMAIN = "airly"
|
DOMAIN = "airly"
|
||||||
|
MAX_REQUESTS_PER_DAY = 100
|
||||||
NO_AIRLY_SENSORS = "There are no Airly sensors in this area yet."
|
NO_AIRLY_SENSORS = "There are no Airly sensors in this area yet."
|
||||||
|
@@ -18,7 +18,6 @@ from .const import (
|
|||||||
ATTR_API_PM1,
|
ATTR_API_PM1,
|
||||||
ATTR_API_PRESSURE,
|
ATTR_API_PRESSURE,
|
||||||
ATTR_API_TEMPERATURE,
|
ATTR_API_TEMPERATURE,
|
||||||
DATA_CLIENT,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,14 +59,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
"""Set up Airly sensor entities based on a config entry."""
|
"""Set up Airly sensor entities based on a config entry."""
|
||||||
name = config_entry.data[CONF_NAME]
|
name = config_entry.data[CONF_NAME]
|
||||||
|
|
||||||
data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
sensors = []
|
sensors = []
|
||||||
for sensor in SENSOR_TYPES:
|
for sensor in SENSOR_TYPES:
|
||||||
unique_id = f"{config_entry.unique_id}-{sensor.lower()}"
|
unique_id = f"{config_entry.unique_id}-{sensor.lower()}"
|
||||||
sensors.append(AirlySensor(data, name, sensor, unique_id))
|
sensors.append(AirlySensor(coordinator, name, sensor, unique_id))
|
||||||
|
|
||||||
async_add_entities(sensors, True)
|
async_add_entities(sensors, False)
|
||||||
|
|
||||||
|
|
||||||
def round_state(func):
|
def round_state(func):
|
||||||
@@ -85,10 +84,9 @@ def round_state(func):
|
|||||||
class AirlySensor(Entity):
|
class AirlySensor(Entity):
|
||||||
"""Define an Airly sensor."""
|
"""Define an Airly sensor."""
|
||||||
|
|
||||||
def __init__(self, airly, name, kind, unique_id):
|
def __init__(self, coordinator, name, kind, unique_id):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self.airly = airly
|
self.coordinator = coordinator
|
||||||
self.data = airly.data
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._unique_id = unique_id
|
self._unique_id = unique_id
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
@@ -103,10 +101,15 @@ class AirlySensor(Entity):
|
|||||||
"""Return the name."""
|
"""Return the name."""
|
||||||
return f"{self._name} {SENSOR_TYPES[self.kind][ATTR_LABEL]}"
|
return f"{self._name} {SENSOR_TYPES[self.kind][ATTR_LABEL]}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Return the polling requirement of the entity."""
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state."""
|
"""Return the state."""
|
||||||
self._state = self.data[self.kind]
|
self._state = self.coordinator.data[self.kind]
|
||||||
if self.kind in [ATTR_API_PM1, ATTR_API_PRESSURE]:
|
if self.kind in [ATTR_API_PM1, ATTR_API_PRESSURE]:
|
||||||
self._state = round(self._state)
|
self._state = round(self._state)
|
||||||
if self.kind in [ATTR_API_TEMPERATURE, ATTR_API_HUMIDITY]:
|
if self.kind in [ATTR_API_TEMPERATURE, ATTR_API_HUMIDITY]:
|
||||||
@@ -142,11 +145,16 @@ class AirlySensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return bool(self.data)
|
return self.coordinator.last_update_success
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Connect to dispatcher listening for entity data notifications."""
|
||||||
|
self.coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""Disconnect from update signal."""
|
||||||
|
self.coordinator.async_remove_listener(self.async_write_ha_state)
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the sensor."""
|
"""Update Airly entity."""
|
||||||
await self.airly.async_update()
|
await self.coordinator.async_request_refresh()
|
||||||
|
|
||||||
if self.airly.data:
|
|
||||||
self.data = self.airly.data
|
|
||||||
|
@@ -19,5 +19,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Mostra al mapa l'\u00e0rea geogr\u00e0fica monitoritzada"
|
||||||
|
},
|
||||||
|
"description": "Estableix les diferents opcions de la integraci\u00f3 AirVisual.",
|
||||||
|
"title": "Configuraci\u00f3 d'AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Dieser API-Schl\u00fcssel wird bereits verwendet."
|
"already_configured": "Diese Koordinaten wurden bereits registriert."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel"
|
"invalid_api_key": "Ung\u00fcltiger API-Schl\u00fcssel"
|
||||||
@@ -11,11 +11,24 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"api_key": "API-Schl\u00fcssel",
|
"api_key": "API-Schl\u00fcssel",
|
||||||
"latitude": "Breitengrad",
|
"latitude": "Breitengrad",
|
||||||
"longitude": "L\u00e4ngengrad"
|
"longitude": "L\u00e4ngengrad",
|
||||||
|
"show_on_map": "Zeigen Sie die \u00fcberwachte Geografie auf der Karte an"
|
||||||
},
|
},
|
||||||
|
"description": "\u00dcberwachen Sie die Luftqualit\u00e4t an einem geografischen Ort.",
|
||||||
"title": "Konfigurieren Sie AirVisual"
|
"title": "Konfigurieren Sie AirVisual"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Zeigen Sie die \u00fcberwachte Geografie auf der Karte an"
|
||||||
|
},
|
||||||
|
"description": "Legen Sie verschiedene Optionen f\u00fcr die AirVisual-Integration fest.",
|
||||||
|
"title": "Konfigurieren Sie AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "This API key is already in use."
|
"already_configured": "These coordinates have already been registered."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_key": "Invalid API key"
|
"invalid_api_key": "Invalid API key"
|
||||||
@@ -11,7 +11,8 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"api_key": "API Key",
|
"api_key": "API Key",
|
||||||
"latitude": "Latitude",
|
"latitude": "Latitude",
|
||||||
"longitude": "Longitude"
|
"longitude": "Longitude",
|
||||||
|
"show_on_map": "Show monitored geography on the map"
|
||||||
},
|
},
|
||||||
"description": "Monitor air quality in a geographical location.",
|
"description": "Monitor air quality in a geographical location.",
|
||||||
"title": "Configure AirVisual"
|
"title": "Configure AirVisual"
|
||||||
|
@@ -19,5 +19,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Mostrar geograf\u00eda monitorizada en el mapa"
|
||||||
|
},
|
||||||
|
"description": "Ajustar varias opciones para la integraci\u00f3n de AirVisual.",
|
||||||
|
"title": "Configurar AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
31
homeassistant/components/airvisual/.translations/fr.json
Normal file
31
homeassistant/components/airvisual/.translations/fr.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Cette cl\u00e9 API est d\u00e9j\u00e0 utilis\u00e9e."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"invalid_api_key": "Cl\u00e9 API invalide"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"api_key": "Cl\u00e9 API",
|
||||||
|
"latitude": "Latitude",
|
||||||
|
"longitude": "Longitude",
|
||||||
|
"show_on_map": "Afficher la g\u00e9ographie surveill\u00e9e sur la carte"
|
||||||
|
},
|
||||||
|
"description": "Surveiller la qualit\u00e9 de l\u2019air dans un emplacement g\u00e9ographique.",
|
||||||
|
"title": "Configurer AirVisual"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"description": "D\u00e9finissez diverses options pour l'int\u00e9gration d'AirVisual.",
|
||||||
|
"title": "Configurer AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Questa chiave API \u00e8 gi\u00e0 in uso."
|
"already_configured": "Queste coordinate sono gi\u00e0 state registrate."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_key": "Chiave API non valida"
|
"invalid_api_key": "Chiave API non valida"
|
||||||
@@ -19,5 +19,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Mostra l'area geografica monitorata sulla mappa"
|
||||||
|
},
|
||||||
|
"description": "Impostare varie opzioni per l'integrazione AirVisual.",
|
||||||
|
"title": "Configurare AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
34
homeassistant/components/airvisual/.translations/ko.json
Normal file
34
homeassistant/components/airvisual/.translations/ko.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "\uc774 API \ud0a4\ub294 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"invalid_api_key": "\uc798\ubabb\ub41c API \ud0a4"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"api_key": "API \ud0a4",
|
||||||
|
"latitude": "\uc704\ub3c4",
|
||||||
|
"longitude": "\uacbd\ub3c4",
|
||||||
|
"show_on_map": "\uc9c0\ub3c4\uc5d0 \ubaa8\ub2c8\ud130\ub9c1\ub41c \uc9c0\ub9ac \uc815\ubcf4 \ud45c\uc2dc"
|
||||||
|
},
|
||||||
|
"description": "\uc9c0\ub9ac\uc801 \uc704\uce58\uc5d0\uc11c \ub300\uae30\uc9c8\uc744 \ubaa8\ub2c8\ud130\ub9c1\ud569\ub2c8\ub2e4.",
|
||||||
|
"title": "AirVisual \uad6c\uc131"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "\uc9c0\ub3c4\uc5d0 \ubaa8\ub2c8\ud130\ub9c1\ub41c \uc9c0\ub9ac \uc815\ubcf4 \ud45c\uc2dc"
|
||||||
|
},
|
||||||
|
"description": "AirVisual \ud1b5\ud569 \uad6c\uc131\uc694\uc18c\uc5d0 \ub300\ud55c \ub2e4\uc591\ud55c \uc635\uc158\uc744 \uc124\uc815\ud574\uc8fc\uc138\uc694.",
|
||||||
|
"title": "AirVisual \uad6c\uc131"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,5 +17,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"description": "Verschidden Optioune fir d'AirVisual Integratioun d\u00e9fin\u00e9ieren.",
|
||||||
|
"title": "Airvisual ariichten"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Denne API-n\u00f8kkelen er allerede i bruk."
|
"already_configured": "Disse koordinatene er allerede registrert."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_key": "Ugyldig API-n\u00f8kkel"
|
"invalid_api_key": "Ugyldig API-n\u00f8kkel"
|
||||||
@@ -18,6 +18,17 @@
|
|||||||
"title": "Konfigurer AirVisual"
|
"title": "Konfigurer AirVisual"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": ""
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Vis overv\u00e5ket geografi p\u00e5 kartet"
|
||||||
|
},
|
||||||
|
"description": "Angi forskjellige alternativer for AirVisual-integrasjonen.",
|
||||||
|
"title": "Konfigurer AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
34
homeassistant/components/airvisual/.translations/pl.json
Normal file
34
homeassistant/components/airvisual/.translations/pl.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Ten klucz API jest ju\u017c w u\u017cyciu."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"invalid_api_key": "Nieprawid\u0142owy klucz API"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"api_key": "Klucz API",
|
||||||
|
"latitude": "Szeroko\u015b\u0107 geograficzna",
|
||||||
|
"longitude": "D\u0142ugo\u015b\u0107 geograficzna",
|
||||||
|
"show_on_map": "Wy\u015bwietlaj encje na mapie"
|
||||||
|
},
|
||||||
|
"description": "Monitoruj jako\u015b\u0107 powietrza w okre\u015blonej lokalizacji geograficznej.",
|
||||||
|
"title": "Konfiguracja AirVisual"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Wy\u015bwietlaj encje na mapie"
|
||||||
|
},
|
||||||
|
"description": "Konfiguracja opcji integracji AirVisual.",
|
||||||
|
"title": "Konfiguracja AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -19,5 +19,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043d\u0430 \u043a\u0430\u0440\u0442\u0435"
|
||||||
|
},
|
||||||
|
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 AirVisual.",
|
||||||
|
"title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
12
homeassistant/components/airvisual/.translations/sk.json
Normal file
12
homeassistant/components/airvisual/.translations/sk.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"latitude": "Zemepisn\u00e1 \u0161\u00edrka",
|
||||||
|
"longitude": "Zemepisn\u00e1 d\u013a\u017eka"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
homeassistant/components/airvisual/.translations/sl.json
Normal file
34
homeassistant/components/airvisual/.translations/sl.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Ta klju\u010d API je \u017ee v uporabi."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"invalid_api_key": "Neveljaven API klju\u010d"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"api_key": "API Klju\u010d",
|
||||||
|
"latitude": "Zemljepisna \u0161irina",
|
||||||
|
"longitude": "Zemljepisna dol\u017eina",
|
||||||
|
"show_on_map": "Prika\u017ei nadzorovano obmo\u010dje na zemljevidu"
|
||||||
|
},
|
||||||
|
"description": "Spremljajte kakovost zraka na zemljepisni lokaciji.",
|
||||||
|
"title": "Nastavite AirVisual"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "Prika\u017ei nadzorovano obmo\u010dje na zemljevidu"
|
||||||
|
},
|
||||||
|
"description": "Nastavite razli\u010dne mo\u017enosti za integracijo AirVisual.",
|
||||||
|
"title": "Nastavite AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "\u6b64 API \u5bc6\u9470\u5df2\u88ab\u4f7f\u7528\u3002"
|
"already_configured": "\u6b64\u4e9b\u5ea7\u6a19\u5df2\u8a3b\u518a\u3002"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_api_key": "API \u5bc6\u78bc\u7121\u6548"
|
"invalid_api_key": "API \u5bc6\u78bc\u7121\u6548"
|
||||||
@@ -19,5 +19,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "AirVisual"
|
"title": "AirVisual"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"show_on_map": "\u65bc\u5730\u5716\u4e0a\u986f\u793a\u76e3\u63a7\u4f4d\u7f6e\u3002"
|
||||||
|
},
|
||||||
|
"description": "\u8a2d\u5b9a AirVisual \u6574\u5408\u9078\u9805\u3002",
|
||||||
|
"title": "\u8a2d\u5b9a AirVisual"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,4 @@
|
|||||||
"""The airvisual component."""
|
"""The airvisual component."""
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pyairvisual import Client
|
from pyairvisual import Client
|
||||||
@@ -23,7 +22,6 @@ from homeassistant.helpers.event import async_track_time_interval
|
|||||||
from .const import (
|
from .const import (
|
||||||
CONF_CITY,
|
CONF_CITY,
|
||||||
CONF_COUNTRY,
|
CONF_COUNTRY,
|
||||||
CONF_GEOGRAPHIES,
|
|
||||||
DATA_CLIENT,
|
DATA_CLIENT,
|
||||||
DEFAULT_SCAN_INTERVAL,
|
DEFAULT_SCAN_INTERVAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -36,7 +34,7 @@ DATA_LISTENER = "listener"
|
|||||||
|
|
||||||
DEFAULT_OPTIONS = {CONF_SHOW_ON_MAP: True}
|
DEFAULT_OPTIONS = {CONF_SHOW_ON_MAP: True}
|
||||||
|
|
||||||
CONF_NODE_ID = "node_id"
|
CONF_GEOGRAPHIES = "geographies"
|
||||||
|
|
||||||
GEOGRAPHY_COORDINATES_SCHEMA = vol.Schema(
|
GEOGRAPHY_COORDINATES_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
@@ -70,34 +68,38 @@ CONFIG_SCHEMA = vol.Schema({DOMAIN: CLOUD_API_SCHEMA}, extra=vol.ALLOW_EXTRA)
|
|||||||
def async_get_geography_id(geography_dict):
|
def async_get_geography_id(geography_dict):
|
||||||
"""Generate a unique ID from a geography dict."""
|
"""Generate a unique ID from a geography dict."""
|
||||||
if CONF_CITY in geography_dict:
|
if CONF_CITY in geography_dict:
|
||||||
return ",".join(
|
return ", ".join(
|
||||||
(
|
(
|
||||||
geography_dict[CONF_CITY],
|
geography_dict[CONF_CITY],
|
||||||
geography_dict[CONF_STATE],
|
geography_dict[CONF_STATE],
|
||||||
geography_dict[CONF_COUNTRY],
|
geography_dict[CONF_COUNTRY],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return ",".join(
|
return ", ".join(
|
||||||
(str(geography_dict[CONF_LATITUDE]), str(geography_dict[CONF_LONGITUDE]))
|
(str(geography_dict[CONF_LATITUDE]), str(geography_dict[CONF_LONGITUDE]))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the AirVisual component."""
|
"""Set up the AirVisual component."""
|
||||||
hass.data[DOMAIN] = {}
|
hass.data[DOMAIN] = {DATA_CLIENT: {}, DATA_LISTENER: {}}
|
||||||
hass.data[DOMAIN][DATA_CLIENT] = {}
|
|
||||||
hass.data[DOMAIN][DATA_LISTENER] = {}
|
|
||||||
|
|
||||||
if DOMAIN not in config:
|
if DOMAIN not in config:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
conf = config[DOMAIN]
|
conf = config[DOMAIN]
|
||||||
|
|
||||||
hass.async_create_task(
|
for geography in conf.get(
|
||||||
hass.config_entries.flow.async_init(
|
CONF_GEOGRAPHIES,
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=conf
|
[{CONF_LATITUDE: hass.config.latitude, CONF_LONGITUDE: hass.config.longitude}],
|
||||||
|
):
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_IMPORT},
|
||||||
|
data={CONF_API_KEY: conf[CONF_API_KEY], **geography},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -144,6 +146,45 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_entry(hass, config_entry):
|
||||||
|
"""Migrate an old config entry."""
|
||||||
|
version = config_entry.version
|
||||||
|
|
||||||
|
_LOGGER.debug("Migrating from version %s", version)
|
||||||
|
|
||||||
|
# 1 -> 2: One geography per config entry
|
||||||
|
if version == 1:
|
||||||
|
version = config_entry.version = 2
|
||||||
|
|
||||||
|
# Update the config entry to only include the first geography (there is always
|
||||||
|
# guaranteed to be at least one):
|
||||||
|
data = {**config_entry.data}
|
||||||
|
geographies = data.pop(CONF_GEOGRAPHIES)
|
||||||
|
first_geography = geographies.pop(0)
|
||||||
|
first_id = async_get_geography_id(first_geography)
|
||||||
|
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
config_entry,
|
||||||
|
unique_id=first_id,
|
||||||
|
title=f"Cloud API ({first_id})",
|
||||||
|
data={CONF_API_KEY: config_entry.data[CONF_API_KEY], **first_geography},
|
||||||
|
)
|
||||||
|
|
||||||
|
# For any geographies that remain, create a new config entry for each one:
|
||||||
|
for geography in geographies:
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_IMPORT},
|
||||||
|
data={CONF_API_KEY: config_entry.data[CONF_API_KEY], **geography},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER.info("Migration to version %s successful", version)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass, config_entry):
|
async def async_unload_entry(hass, config_entry):
|
||||||
"""Unload an AirVisual config entry."""
|
"""Unload an AirVisual config entry."""
|
||||||
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)
|
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)
|
||||||
@@ -170,40 +211,28 @@ class AirVisualData:
|
|||||||
self._client = client
|
self._client = client
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self.data = {}
|
self.data = {}
|
||||||
|
self.geography_data = config_entry.data
|
||||||
|
self.geography_id = config_entry.unique_id
|
||||||
self.options = config_entry.options
|
self.options = config_entry.options
|
||||||
|
|
||||||
self.geographies = {
|
|
||||||
async_get_geography_id(geography): geography
|
|
||||||
for geography in config_entry.data[CONF_GEOGRAPHIES]
|
|
||||||
}
|
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Get new data for all locations from the AirVisual cloud API."""
|
"""Get new data for all locations from the AirVisual cloud API."""
|
||||||
tasks = []
|
if CONF_CITY in self.geography_data:
|
||||||
|
api_coro = self._client.api.city(
|
||||||
|
self.geography_data[CONF_CITY],
|
||||||
|
self.geography_data[CONF_STATE],
|
||||||
|
self.geography_data[CONF_COUNTRY],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
api_coro = self._client.api.nearest_city(
|
||||||
|
self.geography_data[CONF_LATITUDE], self.geography_data[CONF_LONGITUDE],
|
||||||
|
)
|
||||||
|
|
||||||
for geography in self.geographies.values():
|
try:
|
||||||
if CONF_CITY in geography:
|
self.data[self.geography_id] = await api_coro
|
||||||
tasks.append(
|
except AirVisualError as err:
|
||||||
self._client.api.city(
|
_LOGGER.error("Error while retrieving data: %s", err)
|
||||||
geography[CONF_CITY],
|
self.data[self.geography_id] = {}
|
||||||
geography[CONF_STATE],
|
|
||||||
geography[CONF_COUNTRY],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tasks.append(
|
|
||||||
self._client.api.nearest_city(
|
|
||||||
geography[CONF_LATITUDE], geography[CONF_LONGITUDE],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
||||||
for geography_id, result in zip(self.geographies, results):
|
|
||||||
if isinstance(result, AirVisualError):
|
|
||||||
_LOGGER.error("Error while retrieving data: %s", result)
|
|
||||||
self.data[geography_id] = {}
|
|
||||||
continue
|
|
||||||
self.data[geography_id] = result
|
|
||||||
|
|
||||||
_LOGGER.debug("Received new data")
|
_LOGGER.debug("Received new data")
|
||||||
async_dispatcher_send(self._hass, TOPIC_UPDATE)
|
async_dispatcher_send(self._hass, TOPIC_UPDATE)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
"""Define a config flow manager for AirVisual."""
|
"""Define a config flow manager for AirVisual."""
|
||||||
import logging
|
import asyncio
|
||||||
|
|
||||||
from pyairvisual import Client
|
from pyairvisual import Client
|
||||||
from pyairvisual.errors import InvalidKeyError
|
from pyairvisual.errors import InvalidKeyError
|
||||||
@@ -15,15 +15,14 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
|
|
||||||
from .const import CONF_GEOGRAPHIES, DOMAIN # pylint: disable=unused-import
|
from . import async_get_geography_id
|
||||||
|
from .const import DOMAIN # pylint: disable=unused-import
|
||||||
_LOGGER = logging.getLogger("homeassistant.components.airvisual")
|
|
||||||
|
|
||||||
|
|
||||||
class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle an AirVisual config flow."""
|
"""Handle an AirVisual config flow."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 2
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -68,35 +67,33 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if not user_input:
|
if not user_input:
|
||||||
return await self._show_form()
|
return await self._show_form()
|
||||||
|
|
||||||
await self._async_set_unique_id(user_input[CONF_API_KEY])
|
geo_id = async_get_geography_id(user_input)
|
||||||
|
await self._async_set_unique_id(geo_id)
|
||||||
|
|
||||||
websession = aiohttp_client.async_get_clientsession(self.hass)
|
websession = aiohttp_client.async_get_clientsession(self.hass)
|
||||||
client = Client(websession, api_key=user_input[CONF_API_KEY])
|
client = Client(websession, api_key=user_input[CONF_API_KEY])
|
||||||
|
|
||||||
try:
|
# If this is the first (and only the first) time we've seen this API key, check
|
||||||
await client.api.nearest_city()
|
# that it's valid:
|
||||||
except InvalidKeyError:
|
checked_keys = self.hass.data.setdefault("airvisual_checked_api_keys", set())
|
||||||
return await self._show_form(errors={CONF_API_KEY: "invalid_api_key"})
|
check_keys_lock = self.hass.data.setdefault(
|
||||||
|
"airvisual_checked_api_keys_lock", asyncio.Lock()
|
||||||
data = {CONF_API_KEY: user_input[CONF_API_KEY]}
|
|
||||||
if user_input.get(CONF_GEOGRAPHIES):
|
|
||||||
data[CONF_GEOGRAPHIES] = user_input[CONF_GEOGRAPHIES]
|
|
||||||
else:
|
|
||||||
data[CONF_GEOGRAPHIES] = [
|
|
||||||
{
|
|
||||||
CONF_LATITUDE: user_input.get(
|
|
||||||
CONF_LATITUDE, self.hass.config.latitude
|
|
||||||
),
|
|
||||||
CONF_LONGITUDE: user_input.get(
|
|
||||||
CONF_LONGITUDE, self.hass.config.longitude
|
|
||||||
),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
return self.async_create_entry(
|
|
||||||
title=f"Cloud API (API key: {user_input[CONF_API_KEY][:4]}...)", data=data
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async with check_keys_lock:
|
||||||
|
if user_input[CONF_API_KEY] not in checked_keys:
|
||||||
|
try:
|
||||||
|
await client.api.nearest_city()
|
||||||
|
except InvalidKeyError:
|
||||||
|
return await self._show_form(
|
||||||
|
errors={CONF_API_KEY: "invalid_api_key"}
|
||||||
|
)
|
||||||
|
|
||||||
|
checked_keys.add(user_input[CONF_API_KEY])
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=f"Cloud API ({geo_id})", data=user_input
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AirVisualOptionsFlowHandler(config_entries.OptionsFlow):
|
class AirVisualOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
"""Handle an AirVisual options flow."""
|
"""Handle an AirVisual options flow."""
|
||||||
|
@@ -5,7 +5,6 @@ DOMAIN = "airvisual"
|
|||||||
|
|
||||||
CONF_CITY = "city"
|
CONF_CITY = "city"
|
||||||
CONF_COUNTRY = "country"
|
CONF_COUNTRY = "country"
|
||||||
CONF_GEOGRAPHIES = "geographies"
|
|
||||||
|
|
||||||
DATA_CLIENT = "client"
|
DATA_CLIENT = "client"
|
||||||
|
|
||||||
|
@@ -191,16 +191,19 @@ class AirVisualSensor(Entity):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
geography = self._airvisual.geographies[self._geography_id]
|
if CONF_LATITUDE in self._airvisual.geography_data:
|
||||||
if CONF_LATITUDE in geography:
|
|
||||||
if self._airvisual.options[CONF_SHOW_ON_MAP]:
|
if self._airvisual.options[CONF_SHOW_ON_MAP]:
|
||||||
self._attrs[ATTR_LATITUDE] = geography[CONF_LATITUDE]
|
self._attrs[ATTR_LATITUDE] = self._airvisual.geography_data[
|
||||||
self._attrs[ATTR_LONGITUDE] = geography[CONF_LONGITUDE]
|
CONF_LATITUDE
|
||||||
|
]
|
||||||
|
self._attrs[ATTR_LONGITUDE] = self._airvisual.geography_data[
|
||||||
|
CONF_LONGITUDE
|
||||||
|
]
|
||||||
self._attrs.pop("lati", None)
|
self._attrs.pop("lati", None)
|
||||||
self._attrs.pop("long", None)
|
self._attrs.pop("long", None)
|
||||||
else:
|
else:
|
||||||
self._attrs["lati"] = geography[CONF_LATITUDE]
|
self._attrs["lati"] = self._airvisual.geography_data[CONF_LATITUDE]
|
||||||
self._attrs["long"] = geography[CONF_LONGITUDE]
|
self._attrs["long"] = self._airvisual.geography_data[CONF_LONGITUDE]
|
||||||
self._attrs.pop(ATTR_LATITUDE, None)
|
self._attrs.pop(ATTR_LATITUDE, None)
|
||||||
self._attrs.pop(ATTR_LONGITUDE, None)
|
self._attrs.pop(ATTR_LONGITUDE, None)
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
"invalid_api_key": "Invalid API key"
|
"invalid_api_key": "Invalid API key"
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "This API key is already in use."
|
"already_configured": "These coordinates have already been registered."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
|
@@ -7,10 +7,17 @@
|
|||||||
"disarm": "Desactiva {entity_name}",
|
"disarm": "Desactiva {entity_name}",
|
||||||
"trigger": "Dispara {entity_name}"
|
"trigger": "Dispara {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} est\u00e0 activada en mode 'a fora'",
|
||||||
|
"is_armed_home": "{entity_name} est\u00e0 activada en mode 'a casa'",
|
||||||
|
"is_armed_night": "{entity_name} est\u00e0 activada en mode 'nocturn'",
|
||||||
|
"is_disarmed": "{entity_name} est\u00e0 desactivada",
|
||||||
|
"is_triggered": "{entity_name} est\u00e0 disparada"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} activada en mode a fora",
|
"armed_away": "{entity_name} activada en mode 'a fora'",
|
||||||
"armed_home": "{entity_name} activada en mode a casa",
|
"armed_home": "{entity_name} activada en mode 'a casa'",
|
||||||
"armed_night": "{entity_name} activada en mode nocturn",
|
"armed_night": "{entity_name} activada en mode 'nocturn'",
|
||||||
"disarmed": "{entity_name} desactivada",
|
"disarmed": "{entity_name} desactivada",
|
||||||
"triggered": "{entity_name} disparat/ada"
|
"triggered": "{entity_name} disparat/ada"
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "Deaktivere {entity_name}",
|
"disarm": "Deaktivere {entity_name}",
|
||||||
"trigger": "Ausl\u00f6ser {entity_name}"
|
"trigger": "Ausl\u00f6ser {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} ist aktiviert - Unterwegs",
|
||||||
|
"is_armed_home": "{entity_name} ist aktiviert - Zuhause",
|
||||||
|
"is_armed_night": "{entity_name} ist aktiviert - Nacht",
|
||||||
|
"is_disarmed": "{entity_name} ist deaktiviert",
|
||||||
|
"is_triggered": "{entity_name} wurde ausgel\u00f6st"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} Unterwegs",
|
"armed_away": "{entity_name} Unterwegs",
|
||||||
"armed_home": "{entity_name} Zuhause",
|
"armed_home": "{entity_name} Zuhause",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "Disarm {entity_name}",
|
"disarm": "Disarm {entity_name}",
|
||||||
"trigger": "Trigger {entity_name}"
|
"trigger": "Trigger {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} is armed away",
|
||||||
|
"is_armed_home": "{entity_name} is armed home",
|
||||||
|
"is_armed_night": "{entity_name} is armed night",
|
||||||
|
"is_disarmed": "{entity_name} is disarmed",
|
||||||
|
"is_triggered": "{entity_name} is triggered"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} armed away",
|
"armed_away": "{entity_name} armed away",
|
||||||
"armed_home": "{entity_name} armed home",
|
"armed_home": "{entity_name} armed home",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "Desarmar {entity_name}",
|
"disarm": "Desarmar {entity_name}",
|
||||||
"trigger": "Lanzar {entity_name}"
|
"trigger": "Lanzar {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} est\u00e1 armada fuera",
|
||||||
|
"is_armed_home": "{entity_name} est\u00e1 armada en casa",
|
||||||
|
"is_armed_night": "{entity_name} est\u00e1 armada noche",
|
||||||
|
"is_disarmed": "{entity_name} est\u00e1 desarmada",
|
||||||
|
"is_triggered": "{entity_name} est\u00e1 disparada"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} armado fuera",
|
"armed_away": "{entity_name} armado fuera",
|
||||||
"armed_home": "{entity_name} armado en casa",
|
"armed_home": "{entity_name} armado en casa",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "D\u00e9sarmer {entity_name}",
|
"disarm": "D\u00e9sarmer {entity_name}",
|
||||||
"trigger": "D\u00e9clencheur {entity_name}"
|
"trigger": "D\u00e9clencheur {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} est arm\u00e9",
|
||||||
|
"is_armed_home": "{entity_name} est arm\u00e9 \u00e0 la maison",
|
||||||
|
"is_armed_night": "{entity_name} est arm\u00e9 la nuit",
|
||||||
|
"is_disarmed": "{entity_name} est d\u00e9sarm\u00e9",
|
||||||
|
"is_triggered": "{entity_name} est d\u00e9clench\u00e9"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "Armer {entity_name} en mode \"sortie\"",
|
"armed_away": "Armer {entity_name} en mode \"sortie\"",
|
||||||
"armed_home": "Armer {entity_name} en mode \"maison\"",
|
"armed_home": "Armer {entity_name} en mode \"maison\"",
|
||||||
|
@@ -7,11 +7,18 @@
|
|||||||
"disarm": "Disarmare {entity_name}",
|
"disarm": "Disarmare {entity_name}",
|
||||||
"trigger": "Attivazione {entity_name}"
|
"trigger": "Attivazione {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} \u00e8 attivo in modalit\u00e0 fuori casa",
|
||||||
|
"is_armed_home": "{entity_name} \u00e8 attivo in modalit\u00e0 a casa",
|
||||||
|
"is_armed_night": "{entity_name} \u00e8 attivo in modalit\u00e0 notte",
|
||||||
|
"is_disarmed": "{entity_name} \u00e8 disattivo",
|
||||||
|
"is_triggered": "{entity_name} \u00e8 attivato"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} armata modalit\u00e0 fuori casa",
|
"armed_away": "{entity_name} attivato in modalit\u00e0 fuori casa",
|
||||||
"armed_home": "{entity_name} armata modalit\u00e0 a casa",
|
"armed_home": "{entity_name} attivato in modalit\u00e0 a casa",
|
||||||
"armed_night": "{entity_name} armata modalit\u00e0 notte",
|
"armed_night": "{entity_name} attivato in modalit\u00e0 notte",
|
||||||
"disarmed": "{entity_name} disarmato",
|
"disarmed": "{entity_name} disattivato",
|
||||||
"triggered": "{entity_name} attivato"
|
"triggered": "{entity_name} attivato"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "{entity_name} \uacbd\ube44\ud574\uc81c",
|
"disarm": "{entity_name} \uacbd\ube44\ud574\uc81c",
|
||||||
"trigger": "{entity_name} \ud2b8\ub9ac\uac70"
|
"trigger": "{entity_name} \ud2b8\ub9ac\uac70"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} \uc774(\uac00) \uc678\ucd9c \uacbd\ube44\ubaa8\ub4dc \uc0c1\ud0dc\uc774\uba74",
|
||||||
|
"is_armed_home": "{entity_name} \uc774(\uac00) \uc7ac\uc2e4 \uacbd\ube44\ubaa8\ub4dc \uc0c1\ud0dc\uc774\uba74",
|
||||||
|
"is_armed_night": "{entity_name} \uc774(\uac00) \uc57c\uac04 \uacbd\ube44\ubaa8\ub4dc \uc0c1\ud0dc\uc774\uba74",
|
||||||
|
"is_disarmed": "{entity_name} \uc774(\uac00) \ud574\uc81c \uc0c1\ud0dc\uc774\uba74",
|
||||||
|
"is_triggered": "{entity_name} \uc774(\uac00) \ud2b8\ub9ac\uac70\ub418\uc5c8\uc73c\uba74"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} \uc774(\uac00) \uc678\ucd9c \uacbd\ube44\ubaa8\ub4dc\ub85c \uc124\uc815\ub420 \ub54c",
|
"armed_away": "{entity_name} \uc774(\uac00) \uc678\ucd9c \uacbd\ube44\ubaa8\ub4dc\ub85c \uc124\uc815\ub420 \ub54c",
|
||||||
"armed_home": "{entity_name} \uc774(\uac00) \uc7ac\uc2e4 \uacbd\ube44\ubaa8\ub4dc\ub85c \uc124\uc815\ub420 \ub54c",
|
"armed_home": "{entity_name} \uc774(\uac00) \uc7ac\uc2e4 \uacbd\ube44\ubaa8\ub4dc\ub85c \uc124\uc815\ub420 \ub54c",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "{entity_name} entsch\u00e4rfen",
|
"disarm": "{entity_name} entsch\u00e4rfen",
|
||||||
"trigger": "{entity_name} ausl\u00e9isen"
|
"trigger": "{entity_name} ausl\u00e9isen"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} ass ugeschalt fir Ennerwee",
|
||||||
|
"is_armed_home": "{entity_name} ass ugeschalt fir Doheem",
|
||||||
|
"is_armed_night": "{entity_name} ass ugeschalt fir Nuecht",
|
||||||
|
"is_disarmed": "{entity_name} ass entsch\u00e4rft",
|
||||||
|
"is_triggered": "{entity_name} ass ausgel\u00e9ist"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} ugeschalt fir Ennerwee",
|
"armed_away": "{entity_name} ugeschalt fir Ennerwee",
|
||||||
"armed_home": "{entity_name} ugeschalt fir Doheem",
|
"armed_home": "{entity_name} ugeschalt fir Doheem",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "Deaktiver {entity_name}",
|
"disarm": "Deaktiver {entity_name}",
|
||||||
"trigger": "Utl\u00f8ser {entity_name}"
|
"trigger": "Utl\u00f8ser {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} aktivert borte",
|
||||||
|
"is_armed_home": "{entity_name} aktivert hjemme",
|
||||||
|
"is_armed_night": "{entity_name} aktivert natt",
|
||||||
|
"is_disarmed": "{entity_name} er deaktivert",
|
||||||
|
"is_triggered": "{entity_name} er utl\u00f8st"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} aktivert borte",
|
"armed_away": "{entity_name} aktivert borte",
|
||||||
"armed_home": "{entity_name} aktivert hjemme",
|
"armed_home": "{entity_name} aktivert hjemme",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "rozbr\u00f3j {entity_name}",
|
"disarm": "rozbr\u00f3j {entity_name}",
|
||||||
"trigger": "wyzw\u00f3l {entity_name}"
|
"trigger": "wyzw\u00f3l {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} jest uzbrojony (poza domem)",
|
||||||
|
"is_armed_home": "{entity_name} jest uzbrojony (w domu)",
|
||||||
|
"is_armed_night": "{entity_name} jest uzbrojony (noc)",
|
||||||
|
"is_disarmed": "{entity_name} jest rozbrojony",
|
||||||
|
"is_triggered": "{entity_name} jest wyzwolony"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} zostanie uzbrojony (poza domem)",
|
"armed_away": "{entity_name} zostanie uzbrojony (poza domem)",
|
||||||
"armed_home": "{entity_name} zostanie uzbrojony (w domu)",
|
"armed_home": "{entity_name} zostanie uzbrojony (w domu)",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0445\u0440\u0430\u043d\u0443 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
"disarm": "\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0445\u0440\u0430\u043d\u0443 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
"trigger": "{entity_name} \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442"
|
"trigger": "{entity_name} \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u041d\u0435 \u0434\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
|
"is_armed_home": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u0414\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
|
"is_armed_night": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u041d\u043e\u0447\u044c\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
|
"is_disarmed": "\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u043e\u0445\u0440\u0430\u043d\u0430 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
|
"is_triggered": "{entity_name} \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u041d\u0435 \u0434\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
"armed_away": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u041d\u0435 \u0434\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
"armed_home": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u0414\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
"armed_home": "\u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0445\u0440\u0430\u043d\u044b \"\u0414\u043e\u043c\u0430\" \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 {entity_name}",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "Razoro\u017ei {entity_name}",
|
"disarm": "Razoro\u017ei {entity_name}",
|
||||||
"trigger": "Spro\u017ei {entity_name}"
|
"trigger": "Spro\u017ei {entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name} je oboro\u017een na \"zdoma\"",
|
||||||
|
"is_armed_home": "{entity_name} je oboro\u017een na \"dom\"",
|
||||||
|
"is_armed_night": "{entity_name} je oboro\u017een na \"no\u010d\"",
|
||||||
|
"is_disarmed": "{entity_name} razoro\u017een",
|
||||||
|
"is_triggered": "{entity_name} spro\u017een"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name} oboro\u017een - zdoma",
|
"armed_away": "{entity_name} oboro\u017een - zdoma",
|
||||||
"armed_home": "{entity_name} oboro\u017een - dom",
|
"armed_home": "{entity_name} oboro\u017een - dom",
|
||||||
|
@@ -7,6 +7,13 @@
|
|||||||
"disarm": "\u89e3\u9664{entity_name}",
|
"disarm": "\u89e3\u9664{entity_name}",
|
||||||
"trigger": "\u89f8\u767c{entity_name}"
|
"trigger": "\u89f8\u767c{entity_name}"
|
||||||
},
|
},
|
||||||
|
"condition_type": {
|
||||||
|
"is_armed_away": "{entity_name}\u8a2d\u5b9a\u5916\u51fa",
|
||||||
|
"is_armed_home": "{entity_name}\u8a2d\u5b9a\u5728\u5bb6",
|
||||||
|
"is_armed_night": "{entity_name}\u8a2d\u5b9a\u591c\u9593",
|
||||||
|
"is_disarmed": "{entity_name}\u5df2\u89e3\u9664",
|
||||||
|
"is_triggered": "{entity_name}\u5df2\u89f8\u767c"
|
||||||
|
},
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"armed_away": "{entity_name}\u8a2d\u5b9a\u5916\u51fa",
|
"armed_away": "{entity_name}\u8a2d\u5b9a\u5916\u51fa",
|
||||||
"armed_home": "{entity_name}\u8a2d\u5b9a\u5728\u5bb6",
|
"armed_home": "{entity_name}\u8a2d\u5b9a\u5728\u5bb6",
|
||||||
|
@@ -5,3 +5,10 @@ SUPPORT_ALARM_ARM_AWAY = 2
|
|||||||
SUPPORT_ALARM_ARM_NIGHT = 4
|
SUPPORT_ALARM_ARM_NIGHT = 4
|
||||||
SUPPORT_ALARM_TRIGGER = 8
|
SUPPORT_ALARM_TRIGGER = 8
|
||||||
SUPPORT_ALARM_ARM_CUSTOM_BYPASS = 16
|
SUPPORT_ALARM_ARM_CUSTOM_BYPASS = 16
|
||||||
|
|
||||||
|
CONDITION_TRIGGERED = "is_triggered"
|
||||||
|
CONDITION_DISARMED = "is_disarmed"
|
||||||
|
CONDITION_ARMED_HOME = "is_armed_home"
|
||||||
|
CONDITION_ARMED_AWAY = "is_armed_away"
|
||||||
|
CONDITION_ARMED_NIGHT = "is_armed_night"
|
||||||
|
CONDITION_ARMED_CUSTOM_BYPASS = "is_armed_custom_bypass"
|
||||||
|
162
homeassistant/components/alarm_control_panel/device_condition.py
Normal file
162
homeassistant/components/alarm_control_panel/device_condition.py
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
"""Provide the device automations for Alarm control panel."""
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.alarm_control_panel.const import (
|
||||||
|
SUPPORT_ALARM_ARM_AWAY,
|
||||||
|
SUPPORT_ALARM_ARM_CUSTOM_BYPASS,
|
||||||
|
SUPPORT_ALARM_ARM_HOME,
|
||||||
|
SUPPORT_ALARM_ARM_NIGHT,
|
||||||
|
)
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
|
CONF_CONDITION,
|
||||||
|
CONF_DEVICE_ID,
|
||||||
|
CONF_DOMAIN,
|
||||||
|
CONF_ENTITY_ID,
|
||||||
|
CONF_TYPE,
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||||
|
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||||
|
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||||
|
|
||||||
|
from . import DOMAIN
|
||||||
|
from .const import (
|
||||||
|
CONDITION_ARMED_AWAY,
|
||||||
|
CONDITION_ARMED_CUSTOM_BYPASS,
|
||||||
|
CONDITION_ARMED_HOME,
|
||||||
|
CONDITION_ARMED_NIGHT,
|
||||||
|
CONDITION_DISARMED,
|
||||||
|
CONDITION_TRIGGERED,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONDITION_TYPES = {
|
||||||
|
CONDITION_TRIGGERED,
|
||||||
|
CONDITION_DISARMED,
|
||||||
|
CONDITION_ARMED_HOME,
|
||||||
|
CONDITION_ARMED_AWAY,
|
||||||
|
CONDITION_ARMED_NIGHT,
|
||||||
|
CONDITION_ARMED_CUSTOM_BYPASS,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONDITION_SCHEMA = DEVICE_CONDITION_BASE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||||
|
vol.Required(CONF_TYPE): vol.In(CONDITION_TYPES),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_conditions(
|
||||||
|
hass: HomeAssistant, device_id: str
|
||||||
|
) -> List[Dict[str, str]]:
|
||||||
|
"""List device conditions for Alarm control panel devices."""
|
||||||
|
registry = await entity_registry.async_get_registry(hass)
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# Get all the integrations entities for this device
|
||||||
|
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||||
|
if entry.domain != DOMAIN:
|
||||||
|
continue
|
||||||
|
|
||||||
|
state = hass.states.get(entry.entity_id)
|
||||||
|
|
||||||
|
# We need a state or else we can't populate the different armed conditions
|
||||||
|
if state is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
supported_features = state.attributes["supported_features"]
|
||||||
|
|
||||||
|
# Add conditions for each entity that belongs to this integration
|
||||||
|
conditions += [
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_DISARMED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_TRIGGERED,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
if supported_features & SUPPORT_ALARM_ARM_HOME:
|
||||||
|
conditions.append(
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_ARMED_HOME,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if supported_features & SUPPORT_ALARM_ARM_AWAY:
|
||||||
|
conditions.append(
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_ARMED_AWAY,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if supported_features & SUPPORT_ALARM_ARM_NIGHT:
|
||||||
|
conditions.append(
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_ARMED_NIGHT,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if supported_features & SUPPORT_ALARM_ARM_CUSTOM_BYPASS:
|
||||||
|
conditions.append(
|
||||||
|
{
|
||||||
|
CONF_CONDITION: "device",
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: CONDITION_ARMED_CUSTOM_BYPASS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
|
||||||
|
def async_condition_from_config(
|
||||||
|
config: ConfigType, config_validation: bool
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
|
"""Create a function to test a device condition."""
|
||||||
|
if config_validation:
|
||||||
|
config = CONDITION_SCHEMA(config)
|
||||||
|
if config[CONF_TYPE] == CONDITION_TRIGGERED:
|
||||||
|
state = STATE_ALARM_TRIGGERED
|
||||||
|
elif config[CONF_TYPE] == CONDITION_DISARMED:
|
||||||
|
state = STATE_ALARM_DISARMED
|
||||||
|
elif config[CONF_TYPE] == CONDITION_ARMED_HOME:
|
||||||
|
state = STATE_ALARM_ARMED_HOME
|
||||||
|
elif config[CONF_TYPE] == CONDITION_ARMED_AWAY:
|
||||||
|
state = STATE_ALARM_ARMED_AWAY
|
||||||
|
elif config[CONF_TYPE] == CONDITION_ARMED_NIGHT:
|
||||||
|
state = STATE_ALARM_ARMED_NIGHT
|
||||||
|
elif config[CONF_TYPE] == CONDITION_ARMED_CUSTOM_BYPASS:
|
||||||
|
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
|
||||||
|
|
||||||
|
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
|
||||||
|
"""Test if an entity is a certain state."""
|
||||||
|
return condition.state(hass, config[ATTR_ENTITY_ID], state)
|
||||||
|
|
||||||
|
return test_is_state
|
@@ -1,18 +1,25 @@
|
|||||||
{
|
{
|
||||||
"device_automation": {
|
"device_automation": {
|
||||||
"action_type": {
|
"action_type": {
|
||||||
"arm_away": "Arm {entity_name} away",
|
"arm_away": "Arm {entity_name} away",
|
||||||
"arm_home": "Arm {entity_name} home",
|
"arm_home": "Arm {entity_name} home",
|
||||||
"arm_night": "Arm {entity_name} night",
|
"arm_night": "Arm {entity_name} night",
|
||||||
"disarm": "Disarm {entity_name}",
|
"disarm": "Disarm {entity_name}",
|
||||||
"trigger": "Trigger {entity_name}"
|
"trigger": "Trigger {entity_name}"
|
||||||
},
|
},
|
||||||
"trigger_type": {
|
"condition_type": {
|
||||||
"triggered": "{entity_name} triggered",
|
"is_triggered": "{entity_name} is triggered",
|
||||||
"disarmed": "{entity_name} disarmed",
|
"is_disarmed": "{entity_name} is disarmed",
|
||||||
"armed_home": "{entity_name} armed home",
|
"is_armed_home": "{entity_name} is armed home",
|
||||||
"armed_away": "{entity_name} armed away",
|
"is_armed_away": "{entity_name} is armed away",
|
||||||
"armed_night": "{entity_name} armed night"
|
"is_armed_night": "{entity_name} is armed night"
|
||||||
|
},
|
||||||
|
"trigger_type": {
|
||||||
|
"triggered": "{entity_name} triggered",
|
||||||
|
"disarmed": "{entity_name} disarmed",
|
||||||
|
"armed_home": "{entity_name} armed home",
|
||||||
|
"armed_away": "{entity_name} armed away",
|
||||||
|
"armed_night": "{entity_name} armed night"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@@ -33,6 +33,7 @@ CONF_ZONE_RFID = "rfid"
|
|||||||
CONF_ZONES = "zones"
|
CONF_ZONES = "zones"
|
||||||
CONF_RELAY_ADDR = "relayaddr"
|
CONF_RELAY_ADDR = "relayaddr"
|
||||||
CONF_RELAY_CHAN = "relaychan"
|
CONF_RELAY_CHAN = "relaychan"
|
||||||
|
CONF_CODE_ARM_REQUIRED = "code_arm_required"
|
||||||
|
|
||||||
DEFAULT_DEVICE_TYPE = "socket"
|
DEFAULT_DEVICE_TYPE = "socket"
|
||||||
DEFAULT_DEVICE_HOST = "localhost"
|
DEFAULT_DEVICE_HOST = "localhost"
|
||||||
@@ -42,6 +43,7 @@ DEFAULT_DEVICE_BAUD = 115200
|
|||||||
|
|
||||||
DEFAULT_AUTO_BYPASS = False
|
DEFAULT_AUTO_BYPASS = False
|
||||||
DEFAULT_PANEL_DISPLAY = False
|
DEFAULT_PANEL_DISPLAY = False
|
||||||
|
DEFAULT_CODE_ARM_REQUIRED = True
|
||||||
|
|
||||||
DEFAULT_ZONE_TYPE = "opening"
|
DEFAULT_ZONE_TYPE = "opening"
|
||||||
|
|
||||||
@@ -105,6 +107,9 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
CONF_PANEL_DISPLAY, default=DEFAULT_PANEL_DISPLAY
|
CONF_PANEL_DISPLAY, default=DEFAULT_PANEL_DISPLAY
|
||||||
): cv.boolean,
|
): cv.boolean,
|
||||||
vol.Optional(CONF_AUTO_BYPASS, default=DEFAULT_AUTO_BYPASS): cv.boolean,
|
vol.Optional(CONF_AUTO_BYPASS, default=DEFAULT_AUTO_BYPASS): cv.boolean,
|
||||||
|
vol.Optional(
|
||||||
|
CONF_CODE_ARM_REQUIRED, default=DEFAULT_CODE_ARM_REQUIRED
|
||||||
|
): cv.boolean,
|
||||||
vol.Optional(CONF_ZONES): {vol.Coerce(int): ZONE_SCHEMA},
|
vol.Optional(CONF_ZONES): {vol.Coerce(int): ZONE_SCHEMA},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -121,6 +126,7 @@ def setup(hass, config):
|
|||||||
device = conf[CONF_DEVICE]
|
device = conf[CONF_DEVICE]
|
||||||
display = conf[CONF_PANEL_DISPLAY]
|
display = conf[CONF_PANEL_DISPLAY]
|
||||||
auto_bypass = conf[CONF_AUTO_BYPASS]
|
auto_bypass = conf[CONF_AUTO_BYPASS]
|
||||||
|
code_arm_required = conf[CONF_CODE_ARM_REQUIRED]
|
||||||
zones = conf.get(CONF_ZONES)
|
zones = conf.get(CONF_ZONES)
|
||||||
|
|
||||||
device_type = device[CONF_DEVICE_TYPE]
|
device_type = device[CONF_DEVICE_TYPE]
|
||||||
@@ -206,7 +212,11 @@ def setup(hass, config):
|
|||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_alarmdecoder)
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_alarmdecoder)
|
||||||
|
|
||||||
load_platform(
|
load_platform(
|
||||||
hass, "alarm_control_panel", DOMAIN, {CONF_AUTO_BYPASS: auto_bypass}, config
|
hass,
|
||||||
|
"alarm_control_panel",
|
||||||
|
DOMAIN,
|
||||||
|
{CONF_AUTO_BYPASS: auto_bypass, CONF_CODE_ARM_REQUIRED: code_arm_required},
|
||||||
|
config,
|
||||||
)
|
)
|
||||||
|
|
||||||
if zones:
|
if zones:
|
||||||
|
@@ -21,7 +21,13 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
from . import CONF_AUTO_BYPASS, DATA_AD, DOMAIN, SIGNAL_PANEL_MESSAGE
|
from . import (
|
||||||
|
CONF_AUTO_BYPASS,
|
||||||
|
CONF_CODE_ARM_REQUIRED,
|
||||||
|
DATA_AD,
|
||||||
|
DOMAIN,
|
||||||
|
SIGNAL_PANEL_MESSAGE,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -39,7 +45,8 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
return
|
return
|
||||||
|
|
||||||
auto_bypass = discovery_info[CONF_AUTO_BYPASS]
|
auto_bypass = discovery_info[CONF_AUTO_BYPASS]
|
||||||
entity = AlarmDecoderAlarmPanel(auto_bypass)
|
code_arm_required = discovery_info[CONF_CODE_ARM_REQUIRED]
|
||||||
|
entity = AlarmDecoderAlarmPanel(auto_bypass, code_arm_required)
|
||||||
add_entities([entity])
|
add_entities([entity])
|
||||||
|
|
||||||
def alarm_toggle_chime_handler(service):
|
def alarm_toggle_chime_handler(service):
|
||||||
@@ -70,7 +77,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
||||||
"""Representation of an AlarmDecoder-based alarm panel."""
|
"""Representation of an AlarmDecoder-based alarm panel."""
|
||||||
|
|
||||||
def __init__(self, auto_bypass):
|
def __init__(self, auto_bypass, code_arm_required):
|
||||||
"""Initialize the alarm panel."""
|
"""Initialize the alarm panel."""
|
||||||
self._display = ""
|
self._display = ""
|
||||||
self._name = "Alarm Panel"
|
self._name = "Alarm Panel"
|
||||||
@@ -85,6 +92,7 @@ class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
|||||||
self._ready = None
|
self._ready = None
|
||||||
self._zone_bypassed = None
|
self._zone_bypassed = None
|
||||||
self._auto_bypass = auto_bypass
|
self._auto_bypass = auto_bypass
|
||||||
|
self._code_arm_required = code_arm_required
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
@@ -140,6 +148,11 @@ class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
|||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT
|
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def code_arm_required(self):
|
||||||
|
"""Whether the code is required for arm actions."""
|
||||||
|
return self._code_arm_required
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
@@ -153,6 +166,7 @@ class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
|||||||
"programming_mode": self._programming_mode,
|
"programming_mode": self._programming_mode,
|
||||||
"ready": self._ready,
|
"ready": self._ready,
|
||||||
"zone_bypassed": self._zone_bypassed,
|
"zone_bypassed": self._zone_bypassed,
|
||||||
|
"code_arm_required": self._code_arm_required,
|
||||||
}
|
}
|
||||||
|
|
||||||
def alarm_disarm(self, code=None):
|
def alarm_disarm(self, code=None):
|
||||||
@@ -166,6 +180,8 @@ class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
|||||||
if self._auto_bypass:
|
if self._auto_bypass:
|
||||||
self.hass.data[DATA_AD].send(f"{code!s}6#")
|
self.hass.data[DATA_AD].send(f"{code!s}6#")
|
||||||
self.hass.data[DATA_AD].send(f"{code!s}2")
|
self.hass.data[DATA_AD].send(f"{code!s}2")
|
||||||
|
elif not self._code_arm_required:
|
||||||
|
self.hass.data[DATA_AD].send("#2")
|
||||||
|
|
||||||
def alarm_arm_home(self, code=None):
|
def alarm_arm_home(self, code=None):
|
||||||
"""Send arm home command."""
|
"""Send arm home command."""
|
||||||
@@ -173,11 +189,15 @@ class AlarmDecoderAlarmPanel(AlarmControlPanel):
|
|||||||
if self._auto_bypass:
|
if self._auto_bypass:
|
||||||
self.hass.data[DATA_AD].send(f"{code!s}6#")
|
self.hass.data[DATA_AD].send(f"{code!s}6#")
|
||||||
self.hass.data[DATA_AD].send(f"{code!s}3")
|
self.hass.data[DATA_AD].send(f"{code!s}3")
|
||||||
|
elif not self._code_arm_required:
|
||||||
|
self.hass.data[DATA_AD].send("#3")
|
||||||
|
|
||||||
def alarm_arm_night(self, code=None):
|
def alarm_arm_night(self, code=None):
|
||||||
"""Send arm night command."""
|
"""Send arm night command."""
|
||||||
if code:
|
if code:
|
||||||
self.hass.data[DATA_AD].send(f"{code!s}7")
|
self.hass.data[DATA_AD].send(f"{code!s}7")
|
||||||
|
elif not self._code_arm_required:
|
||||||
|
self.hass.data[DATA_AD].send("#7")
|
||||||
|
|
||||||
def alarm_toggle_chime(self, code=None):
|
def alarm_toggle_chime(self, code=None):
|
||||||
"""Send toggle chime command."""
|
"""Send toggle chime command."""
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
{
|
{
|
||||||
"domain": "alarmdecoder",
|
"domain": "alarmdecoder",
|
||||||
"name": "AlarmDecoder",
|
"name": "AlarmDecoder",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/alarmdecoder",
|
"documentation": "https://www.home-assistant.io/integrations/alarmdecoder",
|
||||||
"requirements": [
|
"requirements": ["alarmdecoder==1.13.2"],
|
||||||
"alarmdecoder==1.13.2"
|
"dependencies": [],
|
||||||
],
|
"codeowners": ["@ajschmidt8"]
|
||||||
"dependencies": [],
|
|
||||||
"codeowners": []
|
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
alarm_keypress:
|
alarm_keypress:
|
||||||
description: Send custom keypresses to the alarm.
|
description: Send custom keypresses to the alarm.
|
||||||
fields:
|
fields:
|
||||||
entity_id:
|
|
||||||
description: Name of the alarm control panel to trigger.
|
|
||||||
example: 'alarm_control_panel.downstairs'
|
|
||||||
keypress:
|
keypress:
|
||||||
description: 'String to send to the alarm panel.'
|
description: 'String to send to the alarm panel.'
|
||||||
example: '*71'
|
example: '*71'
|
||||||
@@ -11,9 +8,6 @@ alarm_keypress:
|
|||||||
alarm_toggle_chime:
|
alarm_toggle_chime:
|
||||||
description: Send the alarm the toggle chime command.
|
description: Send the alarm the toggle chime command.
|
||||||
fields:
|
fields:
|
||||||
entity_id:
|
|
||||||
description: Name of the alarm control panel to trigger.
|
|
||||||
example: 'alarm_control_panel.downstairs'
|
|
||||||
code:
|
code:
|
||||||
description: A required code to toggle the alarm control panel chime with.
|
description: A required code to toggle the alarm control panel chime with.
|
||||||
example: 1234
|
example: 1234
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
"""The alarmdotcom component."""
|
|
@@ -1,132 +0,0 @@
|
|||||||
"""Interfaces with Alarm.com alarm control panels."""
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
|
|
||||||
from pyalarmdotcom import Alarmdotcom
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
import homeassistant.components.alarm_control_panel as alarm
|
|
||||||
from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA
|
|
||||||
from homeassistant.components.alarm_control_panel.const import (
|
|
||||||
SUPPORT_ALARM_ARM_AWAY,
|
|
||||||
SUPPORT_ALARM_ARM_HOME,
|
|
||||||
)
|
|
||||||
from homeassistant.const import (
|
|
||||||
CONF_CODE,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_USERNAME,
|
|
||||||
STATE_ALARM_ARMED_AWAY,
|
|
||||||
STATE_ALARM_ARMED_HOME,
|
|
||||||
STATE_ALARM_DISARMED,
|
|
||||||
)
|
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
DEFAULT_NAME = "Alarm.com"
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_PASSWORD): cv.string,
|
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
|
||||||
vol.Optional(CONF_CODE): cv.positive_int,
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
|
||||||
"""Set up a Alarm.com control panel."""
|
|
||||||
name = config.get(CONF_NAME)
|
|
||||||
code = config.get(CONF_CODE)
|
|
||||||
username = config.get(CONF_USERNAME)
|
|
||||||
password = config.get(CONF_PASSWORD)
|
|
||||||
|
|
||||||
alarmdotcom = AlarmDotCom(hass, name, code, username, password)
|
|
||||||
await alarmdotcom.async_login()
|
|
||||||
async_add_entities([alarmdotcom])
|
|
||||||
|
|
||||||
|
|
||||||
class AlarmDotCom(alarm.AlarmControlPanel):
|
|
||||||
"""Representation of an Alarm.com status."""
|
|
||||||
|
|
||||||
def __init__(self, hass, name, code, username, password):
|
|
||||||
"""Initialize the Alarm.com status."""
|
|
||||||
|
|
||||||
_LOGGER.debug("Setting up Alarm.com...")
|
|
||||||
self._hass = hass
|
|
||||||
self._name = name
|
|
||||||
self._code = str(code) if code else None
|
|
||||||
self._username = username
|
|
||||||
self._password = password
|
|
||||||
self._websession = async_get_clientsession(self._hass)
|
|
||||||
self._state = None
|
|
||||||
self._alarm = Alarmdotcom(username, password, self._websession, hass.loop)
|
|
||||||
|
|
||||||
async def async_login(self):
|
|
||||||
"""Login to Alarm.com."""
|
|
||||||
await self._alarm.async_login()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Fetch the latest state."""
|
|
||||||
await self._alarm.async_update()
|
|
||||||
return self._alarm.state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the alarm."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def code_format(self):
|
|
||||||
"""Return one or more digits/characters."""
|
|
||||||
if self._code is None:
|
|
||||||
return None
|
|
||||||
if isinstance(self._code, str) and re.search("^\\d+$", self._code):
|
|
||||||
return alarm.FORMAT_NUMBER
|
|
||||||
return alarm.FORMAT_TEXT
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
"""Return the state of the device."""
|
|
||||||
if self._alarm.state.lower() == "disarmed":
|
|
||||||
return STATE_ALARM_DISARMED
|
|
||||||
if self._alarm.state.lower() == "armed stay":
|
|
||||||
return STATE_ALARM_ARMED_HOME
|
|
||||||
if self._alarm.state.lower() == "armed away":
|
|
||||||
return STATE_ALARM_ARMED_AWAY
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_features(self) -> int:
|
|
||||||
"""Return the list of supported features."""
|
|
||||||
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_state_attributes(self):
|
|
||||||
"""Return the state attributes."""
|
|
||||||
return {"sensor_status": self._alarm.sensor_status}
|
|
||||||
|
|
||||||
async def async_alarm_disarm(self, code=None):
|
|
||||||
"""Send disarm command."""
|
|
||||||
if self._validate_code(code):
|
|
||||||
await self._alarm.async_alarm_disarm()
|
|
||||||
|
|
||||||
async def async_alarm_arm_home(self, code=None):
|
|
||||||
"""Send arm home command."""
|
|
||||||
if self._validate_code(code):
|
|
||||||
await self._alarm.async_alarm_arm_home()
|
|
||||||
|
|
||||||
async def async_alarm_arm_away(self, code=None):
|
|
||||||
"""Send arm away command."""
|
|
||||||
if self._validate_code(code):
|
|
||||||
await self._alarm.async_alarm_arm_away()
|
|
||||||
|
|
||||||
def _validate_code(self, code):
|
|
||||||
"""Validate given code."""
|
|
||||||
check = self._code is None or code == self._code
|
|
||||||
if not check:
|
|
||||||
_LOGGER.warning("Wrong code entered")
|
|
||||||
return check
|
|
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "alarmdotcom",
|
|
||||||
"name": "Alarm.com",
|
|
||||||
"documentation": "https://www.home-assistant.io/integrations/alarmdotcom",
|
|
||||||
"requirements": ["pyalarmdotcom==0.3.2"],
|
|
||||||
"dependencies": [],
|
|
||||||
"codeowners": []
|
|
||||||
}
|
|
@@ -98,11 +98,7 @@ async def async_setup(hass, config):
|
|||||||
f"send command {data['request']['namespace']}/{data['request']['name']}"
|
f"send command {data['request']['namespace']}/{data['request']['name']}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {"name": "Amazon Alexa", "message": message, "entity_id": entity_id}
|
||||||
"name": "Amazon Alexa",
|
|
||||||
"message": message,
|
|
||||||
"entity_id": entity_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.components.logbook.async_describe_event(
|
hass.components.logbook.async_describe_event(
|
||||||
DOMAIN, EVENT_ALEXA_SMART_HOME, async_describe_logbook_event
|
DOMAIN, EVENT_ALEXA_SMART_HOME, async_describe_logbook_event
|
||||||
|
@@ -169,6 +169,11 @@ class AlexaCapability:
|
|||||||
"""Return the supportedOperations object."""
|
"""Return the supportedOperations object."""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def camera_stream_configurations():
|
||||||
|
"""Applicable only to CameraStreamController."""
|
||||||
|
return None
|
||||||
|
|
||||||
def serialize_discovery(self):
|
def serialize_discovery(self):
|
||||||
"""Serialize according to the Discovery API."""
|
"""Serialize according to the Discovery API."""
|
||||||
result = {"type": "AlexaInterface", "interface": self.name(), "version": "3"}
|
result = {"type": "AlexaInterface", "interface": self.name(), "version": "3"}
|
||||||
@@ -222,6 +227,10 @@ class AlexaCapability:
|
|||||||
if inputs:
|
if inputs:
|
||||||
result["inputs"] = inputs
|
result["inputs"] = inputs
|
||||||
|
|
||||||
|
camera_stream_configurations = self.camera_stream_configurations()
|
||||||
|
if camera_stream_configurations:
|
||||||
|
result["cameraStreamConfigurations"] = camera_stream_configurations
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def serialize_properties(self):
|
def serialize_properties(self):
|
||||||
@@ -1854,3 +1863,40 @@ class AlexaTimeHoldController(AlexaCapability):
|
|||||||
When false, Alexa does not send the Resume directive.
|
When false, Alexa does not send the Resume directive.
|
||||||
"""
|
"""
|
||||||
return {"allowRemoteResume": self._allow_remote_resume}
|
return {"allowRemoteResume": self._allow_remote_resume}
|
||||||
|
|
||||||
|
|
||||||
|
class AlexaCameraStreamController(AlexaCapability):
|
||||||
|
"""Implements Alexa.CameraStreamController.
|
||||||
|
|
||||||
|
https://developer.amazon.com/docs/device-apis/alexa-camerastreamcontroller.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
supported_locales = {
|
||||||
|
"de-DE",
|
||||||
|
"en-AU",
|
||||||
|
"en-CA",
|
||||||
|
"en-GB",
|
||||||
|
"en-IN",
|
||||||
|
"en-US",
|
||||||
|
"es-ES",
|
||||||
|
"fr-FR",
|
||||||
|
"it-IT",
|
||||||
|
"ja-JP",
|
||||||
|
}
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
"""Return the Alexa API name of this interface."""
|
||||||
|
return "Alexa.CameraStreamController"
|
||||||
|
|
||||||
|
def camera_stream_configurations(self):
|
||||||
|
"""Return cameraStreamConfigurations object."""
|
||||||
|
camera_stream_configurations = [
|
||||||
|
{
|
||||||
|
"protocols": ["HLS"],
|
||||||
|
"resolutions": [{"width": 1280, "height": 720}],
|
||||||
|
"authorizationTypes": ["NONE"],
|
||||||
|
"videoCodecs": ["H264"],
|
||||||
|
"audioCodecs": ["AAC"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return camera_stream_configurations
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
"""Alexa entity adapters."""
|
"""Alexa entity adapters."""
|
||||||
|
import logging
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from homeassistant.components import (
|
from homeassistant.components import (
|
||||||
alarm_control_panel,
|
alarm_control_panel,
|
||||||
alert,
|
alert,
|
||||||
automation,
|
automation,
|
||||||
binary_sensor,
|
binary_sensor,
|
||||||
|
camera,
|
||||||
cover,
|
cover,
|
||||||
fan,
|
fan,
|
||||||
group,
|
group,
|
||||||
@@ -33,11 +36,13 @@ from homeassistant.const import (
|
|||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers import network
|
||||||
from homeassistant.util.decorator import Registry
|
from homeassistant.util.decorator import Registry
|
||||||
|
|
||||||
from .capabilities import (
|
from .capabilities import (
|
||||||
Alexa,
|
Alexa,
|
||||||
AlexaBrightnessController,
|
AlexaBrightnessController,
|
||||||
|
AlexaCameraStreamController,
|
||||||
AlexaChannelController,
|
AlexaChannelController,
|
||||||
AlexaColorController,
|
AlexaColorController,
|
||||||
AlexaColorTemperatureController,
|
AlexaColorTemperatureController,
|
||||||
@@ -68,6 +73,8 @@ from .capabilities import (
|
|||||||
)
|
)
|
||||||
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
|
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ENTITY_ADAPTERS = Registry()
|
ENTITY_ADAPTERS = Registry()
|
||||||
|
|
||||||
TRANSLATION_TABLE = dict.fromkeys(map(ord, r"}{\/|\"()[]+~!><*%"), None)
|
TRANSLATION_TABLE = dict.fromkeys(map(ord, r"}{\/|\"()[]+~!><*%"), None)
|
||||||
@@ -763,3 +770,41 @@ class VacuumCapabilities(AlexaEntity):
|
|||||||
|
|
||||||
yield AlexaEndpointHealth(self.hass, self.entity)
|
yield AlexaEndpointHealth(self.hass, self.entity)
|
||||||
yield Alexa(self.hass)
|
yield Alexa(self.hass)
|
||||||
|
|
||||||
|
|
||||||
|
@ENTITY_ADAPTERS.register(camera.DOMAIN)
|
||||||
|
class CameraCapabilities(AlexaEntity):
|
||||||
|
"""Class to represent Camera capabilities."""
|
||||||
|
|
||||||
|
def default_display_categories(self):
|
||||||
|
"""Return the display categories for this entity."""
|
||||||
|
return [DisplayCategory.CAMERA]
|
||||||
|
|
||||||
|
def interfaces(self):
|
||||||
|
"""Yield the supported interfaces."""
|
||||||
|
if self._check_requirements():
|
||||||
|
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
|
if supported & camera.SUPPORT_STREAM:
|
||||||
|
yield AlexaCameraStreamController(self.entity)
|
||||||
|
|
||||||
|
yield AlexaEndpointHealth(self.hass, self.entity)
|
||||||
|
yield Alexa(self.hass)
|
||||||
|
|
||||||
|
def _check_requirements(self):
|
||||||
|
"""Check the hass URL for HTTPS scheme and port 443."""
|
||||||
|
if "stream" not in self.hass.config.components:
|
||||||
|
_LOGGER.error(
|
||||||
|
"%s requires stream component for AlexaCameraStreamController",
|
||||||
|
self.entity_id,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
url = urlparse(network.async_get_external_url(self.hass))
|
||||||
|
if url.scheme != "https" or (url.port is not None and url.port != 443):
|
||||||
|
_LOGGER.error(
|
||||||
|
"%s requires HTTPS support on port 443 for AlexaCameraStreamController",
|
||||||
|
self.entity_id,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
@@ -4,6 +4,7 @@ import math
|
|||||||
|
|
||||||
from homeassistant import core as ha
|
from homeassistant import core as ha
|
||||||
from homeassistant.components import (
|
from homeassistant.components import (
|
||||||
|
camera,
|
||||||
cover,
|
cover,
|
||||||
fan,
|
fan,
|
||||||
group,
|
group,
|
||||||
@@ -41,6 +42,7 @@ from homeassistant.const import (
|
|||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers import network
|
||||||
import homeassistant.util.color as color_util
|
import homeassistant.util.color as color_util
|
||||||
from homeassistant.util.decorator import Registry
|
from homeassistant.util.decorator import Registry
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
@@ -1523,3 +1525,28 @@ async def async_api_resume(hass, config, directive, context):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return directive.response()
|
return directive.response()
|
||||||
|
|
||||||
|
|
||||||
|
@HANDLERS.register(("Alexa.CameraStreamController", "InitializeCameraStreams"))
|
||||||
|
async def async_api_initialize_camera_stream(hass, config, directive, context):
|
||||||
|
"""Process a InitializeCameraStreams request."""
|
||||||
|
entity = directive.entity
|
||||||
|
stream_source = await camera.async_request_stream(hass, entity.entity_id, fmt="hls")
|
||||||
|
camera_image = hass.states.get(entity.entity_id).attributes["entity_picture"]
|
||||||
|
external_url = network.async_get_external_url(hass)
|
||||||
|
payload = {
|
||||||
|
"cameraStreams": [
|
||||||
|
{
|
||||||
|
"uri": f"{external_url}{stream_source}",
|
||||||
|
"protocol": "HLS",
|
||||||
|
"resolution": {"width": 1280, "height": 720},
|
||||||
|
"authorizationType": "NONE",
|
||||||
|
"videoCodec": "H264",
|
||||||
|
"audioCodec": "AAC",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"imageUri": f"{external_url}{camera_image}",
|
||||||
|
}
|
||||||
|
return directive.response(
|
||||||
|
name="Response", namespace="Alexa.CameraStreamController", payload=payload
|
||||||
|
)
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/alexa",
|
"documentation": "https://www.home-assistant.io/integrations/alexa",
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"dependencies": ["http"],
|
"dependencies": ["http"],
|
||||||
"after_dependencies": ["logbook"],
|
"after_dependencies": ["logbook", "camera"],
|
||||||
"codeowners": ["@home-assistant/cloud", "@ochlocracy"]
|
"codeowners": ["@home-assistant/cloud", "@ochlocracy"]
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,6 @@
|
|||||||
"title": "Velg autentiseringsmetode"
|
"title": "Velg autentiseringsmetode"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Almond"
|
"title": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -18,6 +18,6 @@
|
|||||||
"title": "Autensiere Ambiclimate"
|
"title": "Autensiere Ambiclimate"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Ambiclimate"
|
"title": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Cette cl\u00e9 d'application est d\u00e9j\u00e0 utilis\u00e9e."
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"identifier_exists": "Cl\u00e9 d'application et / ou cl\u00e9 API d\u00e9j\u00e0 enregistr\u00e9e",
|
"identifier_exists": "Cl\u00e9 d'application et / ou cl\u00e9 API d\u00e9j\u00e0 enregistr\u00e9e",
|
||||||
"invalid_key": "Cl\u00e9 d'API et / ou cl\u00e9 d'application non valide",
|
"invalid_key": "Cl\u00e9 d'API et / ou cl\u00e9 d'application non valide",
|
||||||
|
@@ -17,6 +17,6 @@
|
|||||||
"title": "Fyll ut informasjonen din"
|
"title": "Fyll ut informasjonen din"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Ambient PWS"
|
"title": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Ta klju\u010d za aplikacijo je \u017ee v uporabi."
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"identifier_exists": "Aplikacijski klju\u010d in / ali klju\u010d API je \u017ee registriran",
|
"identifier_exists": "Aplikacijski klju\u010d in / ali klju\u010d API je \u017ee registriran",
|
||||||
"invalid_key": "Neveljaven klju\u010d API in / ali klju\u010d aplikacije",
|
"invalid_key": "Neveljaven klju\u010d API in / ali klju\u010d aplikacije",
|
||||||
|
@@ -41,7 +41,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
DATA_CONFIG = "config"
|
DATA_CONFIG = "config"
|
||||||
|
|
||||||
DEFAULT_SOCKET_MIN_RETRY = 15
|
DEFAULT_SOCKET_MIN_RETRY = 15
|
||||||
DEFAULT_WATCHDOG_SECONDS = 5 * 60
|
|
||||||
|
|
||||||
TYPE_24HOURRAININ = "24hourrainin"
|
TYPE_24HOURRAININ = "24hourrainin"
|
||||||
TYPE_BAROMABSIN = "baromabsin"
|
TYPE_BAROMABSIN = "baromabsin"
|
||||||
@@ -342,7 +341,6 @@ class AmbientStation:
|
|||||||
self._config_entry = config_entry
|
self._config_entry = config_entry
|
||||||
self._entry_setup_complete = False
|
self._entry_setup_complete = False
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._watchdog_listener = None
|
|
||||||
self._ws_reconnect_delay = DEFAULT_SOCKET_MIN_RETRY
|
self._ws_reconnect_delay = DEFAULT_SOCKET_MIN_RETRY
|
||||||
self.client = client
|
self.client = client
|
||||||
self.stations = {}
|
self.stations = {}
|
||||||
@@ -359,21 +357,9 @@ class AmbientStation:
|
|||||||
async def ws_connect(self):
|
async def ws_connect(self):
|
||||||
"""Register handlers and connect to the websocket."""
|
"""Register handlers and connect to the websocket."""
|
||||||
|
|
||||||
async def _ws_reconnect(event_time):
|
|
||||||
"""Forcibly disconnect from and reconnect to the websocket."""
|
|
||||||
_LOGGER.debug("Watchdog expired; forcing socket reconnection")
|
|
||||||
await self.client.websocket.disconnect()
|
|
||||||
await self._attempt_connect()
|
|
||||||
|
|
||||||
def on_connect():
|
def on_connect():
|
||||||
"""Define a handler to fire when the websocket is connected."""
|
"""Define a handler to fire when the websocket is connected."""
|
||||||
_LOGGER.info("Connected to websocket")
|
_LOGGER.info("Connected to websocket")
|
||||||
_LOGGER.debug("Watchdog starting")
|
|
||||||
if self._watchdog_listener is not None:
|
|
||||||
self._watchdog_listener()
|
|
||||||
self._watchdog_listener = async_call_later(
|
|
||||||
self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect
|
|
||||||
)
|
|
||||||
|
|
||||||
def on_data(data):
|
def on_data(data):
|
||||||
"""Define a handler to fire when the data is received."""
|
"""Define a handler to fire when the data is received."""
|
||||||
@@ -385,12 +371,6 @@ class AmbientStation:
|
|||||||
self._hass, f"ambient_station_data_update_{mac_address}"
|
self._hass, f"ambient_station_data_update_{mac_address}"
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER.debug("Resetting watchdog")
|
|
||||||
self._watchdog_listener()
|
|
||||||
self._watchdog_listener = async_call_later(
|
|
||||||
self._hass, DEFAULT_WATCHDOG_SECONDS, _ws_reconnect
|
|
||||||
)
|
|
||||||
|
|
||||||
def on_disconnect():
|
def on_disconnect():
|
||||||
"""Define a handler to fire when the websocket is disconnected."""
|
"""Define a handler to fire when the websocket is disconnected."""
|
||||||
_LOGGER.info("Disconnected from websocket")
|
_LOGGER.info("Disconnected from websocket")
|
||||||
@@ -520,13 +500,22 @@ class AmbientWeatherEntity(Entity):
|
|||||||
@callback
|
@callback
|
||||||
def update():
|
def update():
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
self.async_schedule_update_ha_state(True)
|
self.update_from_latest_data()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
|
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
|
||||||
self.hass, f"ambient_station_data_update_{self._mac_address}", update
|
self.hass, f"ambient_station_data_update_{self._mac_address}", update
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.update_from_latest_data()
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self):
|
async def async_will_remove_from_hass(self):
|
||||||
"""Disconnect dispatcher listener when removed."""
|
"""Disconnect dispatcher listener when removed."""
|
||||||
if self._async_unsub_dispatcher_connect:
|
if self._async_unsub_dispatcher_connect:
|
||||||
self._async_unsub_dispatcher_connect()
|
self._async_unsub_dispatcher_connect()
|
||||||
|
self._async_unsub_dispatcher_connect = None
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def update_from_latest_data(self):
|
||||||
|
"""Update the entity from the latest data."""
|
||||||
|
raise NotImplementedError
|
||||||
|
@@ -3,6 +3,7 @@ import logging
|
|||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
from homeassistant.const import ATTR_NAME
|
from homeassistant.const import ATTR_NAME
|
||||||
|
from homeassistant.core import callback
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
SENSOR_TYPES,
|
SENSOR_TYPES,
|
||||||
@@ -76,7 +77,8 @@ class AmbientWeatherBinarySensor(AmbientWeatherEntity, BinarySensorDevice):
|
|||||||
|
|
||||||
return self._state == 1
|
return self._state == 1
|
||||||
|
|
||||||
async def async_update(self):
|
@callback
|
||||||
|
def update_from_latest_data(self):
|
||||||
"""Fetch new state data for the entity."""
|
"""Fetch new state data for the entity."""
|
||||||
self._state = self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
|
self._state = self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
|
||||||
self._sensor_type
|
self._sensor_type
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"name": "Ambient Weather Station",
|
"name": "Ambient Weather Station",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ambient_station",
|
"documentation": "https://www.home-assistant.io/integrations/ambient_station",
|
||||||
"requirements": ["aioambient==1.0.4"],
|
"requirements": ["aioambient==1.1.0"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@bachya"]
|
"codeowners": ["@bachya"]
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.const import ATTR_NAME
|
from homeassistant.const import ATTR_NAME
|
||||||
|
from homeassistant.core import callback
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
SENSOR_TYPES,
|
SENSOR_TYPES,
|
||||||
@@ -74,7 +75,8 @@ class AmbientWeatherSensor(AmbientWeatherEntity):
|
|||||||
"""Return the unit of measurement."""
|
"""Return the unit of measurement."""
|
||||||
return self._unit
|
return self._unit
|
||||||
|
|
||||||
async def async_update(self):
|
@callback
|
||||||
|
def update_from_latest_data(self):
|
||||||
"""Fetch new state data for the sensor."""
|
"""Fetch new state data for the sensor."""
|
||||||
if self._sensor_type == TYPE_SOLARRADIATION_LX:
|
if self._sensor_type == TYPE_SOLARRADIATION_LX:
|
||||||
# If the user requests the solarradiation_lx sensor, use the
|
# If the user requests the solarradiation_lx sensor, use the
|
||||||
|
@@ -42,6 +42,8 @@ from .const import (
|
|||||||
DATA_AMCREST,
|
DATA_AMCREST,
|
||||||
DEVICES,
|
DEVICES,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
SENSOR_EVENT_CODE,
|
||||||
|
SERVICE_EVENT,
|
||||||
SERVICE_UPDATE,
|
SERVICE_UPDATE,
|
||||||
)
|
)
|
||||||
from .helpers import service_signal
|
from .helpers import service_signal
|
||||||
@@ -96,9 +98,11 @@ AMCREST_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string,
|
vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string,
|
||||||
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period,
|
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period,
|
||||||
vol.Optional(CONF_BINARY_SENSORS): vol.All(
|
vol.Optional(CONF_BINARY_SENSORS): vol.All(
|
||||||
cv.ensure_list, [vol.In(BINARY_SENSORS)]
|
cv.ensure_list, [vol.In(BINARY_SENSORS)], vol.Unique()
|
||||||
|
),
|
||||||
|
vol.Optional(CONF_SENSORS): vol.All(
|
||||||
|
cv.ensure_list, [vol.In(SENSORS)], vol.Unique()
|
||||||
),
|
),
|
||||||
vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [vol.In(SENSORS)]),
|
|
||||||
vol.Optional(CONF_CONTROL_LIGHT, default=True): cv.boolean,
|
vol.Optional(CONF_CONTROL_LIGHT, default=True): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -119,6 +123,8 @@ class AmcrestChecker(Http):
|
|||||||
self._wrap_errors = 0
|
self._wrap_errors = 0
|
||||||
self._wrap_lock = threading.Lock()
|
self._wrap_lock = threading.Lock()
|
||||||
self._wrap_login_err = False
|
self._wrap_login_err = False
|
||||||
|
self._wrap_event_flag = threading.Event()
|
||||||
|
self._wrap_event_flag.set()
|
||||||
self._unsub_recheck = None
|
self._unsub_recheck = None
|
||||||
super().__init__(
|
super().__init__(
|
||||||
host,
|
host,
|
||||||
@@ -134,16 +140,22 @@ class AmcrestChecker(Http):
|
|||||||
"""Return if camera's API is responding."""
|
"""Return if camera's API is responding."""
|
||||||
return self._wrap_errors <= MAX_ERRORS and not self._wrap_login_err
|
return self._wrap_errors <= MAX_ERRORS and not self._wrap_login_err
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_flag(self):
|
||||||
|
"""Return threading event flag that indicates if camera's API is responding."""
|
||||||
|
return self._wrap_event_flag
|
||||||
|
|
||||||
def _start_recovery(self):
|
def _start_recovery(self):
|
||||||
|
self._wrap_event_flag.clear()
|
||||||
dispatcher_send(self._hass, service_signal(SERVICE_UPDATE, self._wrap_name))
|
dispatcher_send(self._hass, service_signal(SERVICE_UPDATE, self._wrap_name))
|
||||||
self._unsub_recheck = track_time_interval(
|
self._unsub_recheck = track_time_interval(
|
||||||
self._hass, self._wrap_test_online, RECHECK_INTERVAL
|
self._hass, self._wrap_test_online, RECHECK_INTERVAL
|
||||||
)
|
)
|
||||||
|
|
||||||
def command(self, cmd, retries=None, timeout_cmd=None, stream=False):
|
def command(self, *args, **kwargs):
|
||||||
"""amcrest.Http.command wrapper to catch errors."""
|
"""amcrest.Http.command wrapper to catch errors."""
|
||||||
try:
|
try:
|
||||||
ret = super().command(cmd, retries, timeout_cmd, stream)
|
ret = super().command(*args, **kwargs)
|
||||||
except LoginError as ex:
|
except LoginError as ex:
|
||||||
with self._wrap_lock:
|
with self._wrap_lock:
|
||||||
was_online = self.available
|
was_online = self.available
|
||||||
@@ -172,6 +184,7 @@ class AmcrestChecker(Http):
|
|||||||
self._unsub_recheck()
|
self._unsub_recheck()
|
||||||
self._unsub_recheck = None
|
self._unsub_recheck = None
|
||||||
_LOGGER.error("%s camera back online", self._wrap_name)
|
_LOGGER.error("%s camera back online", self._wrap_name)
|
||||||
|
self._wrap_event_flag.set()
|
||||||
dispatcher_send(self._hass, service_signal(SERVICE_UPDATE, self._wrap_name))
|
dispatcher_send(self._hass, service_signal(SERVICE_UPDATE, self._wrap_name))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@@ -184,6 +197,31 @@ class AmcrestChecker(Http):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _monitor_events(hass, name, api, event_codes):
|
||||||
|
event_codes = ",".join(event_codes)
|
||||||
|
while True:
|
||||||
|
api.available_flag.wait()
|
||||||
|
try:
|
||||||
|
for code, start in api.event_actions(event_codes, retries=5):
|
||||||
|
signal = service_signal(SERVICE_EVENT, name, code)
|
||||||
|
_LOGGER.debug("Sending signal: '%s': %s", signal, start)
|
||||||
|
dispatcher_send(hass, signal, start)
|
||||||
|
except AmcrestError as error:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Error while processing events from %s camera: %r", name, error
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _start_event_monitor(hass, name, api, event_codes):
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=_monitor_events,
|
||||||
|
name=f"Amcrest {name}",
|
||||||
|
args=(hass, name, api, event_codes),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Set up the Amcrest IP Camera component."""
|
"""Set up the Amcrest IP Camera component."""
|
||||||
hass.data.setdefault(DATA_AMCREST, {DEVICES: {}, CAMERAS: []})
|
hass.data.setdefault(DATA_AMCREST, {DEVICES: {}, CAMERAS: []})
|
||||||
@@ -230,6 +268,13 @@ def setup(hass, config):
|
|||||||
{CONF_NAME: name, CONF_BINARY_SENSORS: binary_sensors},
|
{CONF_NAME: name, CONF_BINARY_SENSORS: binary_sensors},
|
||||||
config,
|
config,
|
||||||
)
|
)
|
||||||
|
event_codes = [
|
||||||
|
BINARY_SENSORS[sensor_type][SENSOR_EVENT_CODE]
|
||||||
|
for sensor_type in binary_sensors
|
||||||
|
if BINARY_SENSORS[sensor_type][SENSOR_EVENT_CODE] is not None
|
||||||
|
]
|
||||||
|
if event_codes:
|
||||||
|
_start_event_monitor(hass, name, api, event_codes)
|
||||||
|
|
||||||
if sensors:
|
if sensors:
|
||||||
discovery.load_platform(
|
discovery.load_platform(
|
||||||
|
@@ -10,12 +10,17 @@ from homeassistant.components.binary_sensor import (
|
|||||||
BinarySensorDevice,
|
BinarySensorDevice,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_BINARY_SENSORS, CONF_NAME
|
from homeassistant.const import CONF_BINARY_SENSORS, CONF_NAME
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
BINARY_SENSOR_SCAN_INTERVAL_SECS,
|
BINARY_SENSOR_SCAN_INTERVAL_SECS,
|
||||||
DATA_AMCREST,
|
DATA_AMCREST,
|
||||||
DEVICES,
|
DEVICES,
|
||||||
|
SENSOR_DEVICE_CLASS,
|
||||||
|
SENSOR_EVENT_CODE,
|
||||||
|
SENSOR_NAME,
|
||||||
|
SERVICE_EVENT,
|
||||||
SERVICE_UPDATE,
|
SERVICE_UPDATE,
|
||||||
)
|
)
|
||||||
from .helpers import log_update_error, service_signal
|
from .helpers import log_update_error, service_signal
|
||||||
@@ -26,11 +31,20 @@ SCAN_INTERVAL = timedelta(seconds=BINARY_SENSOR_SCAN_INTERVAL_SECS)
|
|||||||
|
|
||||||
BINARY_SENSOR_MOTION_DETECTED = "motion_detected"
|
BINARY_SENSOR_MOTION_DETECTED = "motion_detected"
|
||||||
BINARY_SENSOR_ONLINE = "online"
|
BINARY_SENSOR_ONLINE = "online"
|
||||||
# Binary sensor types are defined like: Name, device class
|
|
||||||
BINARY_SENSORS = {
|
BINARY_SENSORS = {
|
||||||
BINARY_SENSOR_MOTION_DETECTED: ("Motion Detected", DEVICE_CLASS_MOTION),
|
BINARY_SENSOR_MOTION_DETECTED: (
|
||||||
BINARY_SENSOR_ONLINE: ("Online", DEVICE_CLASS_CONNECTIVITY),
|
"Motion Detected",
|
||||||
|
DEVICE_CLASS_MOTION,
|
||||||
|
"VideoMotion",
|
||||||
|
),
|
||||||
|
BINARY_SENSOR_ONLINE: ("Online", DEVICE_CLASS_CONNECTIVITY, None),
|
||||||
}
|
}
|
||||||
|
BINARY_SENSORS = {
|
||||||
|
k: dict(zip((SENSOR_NAME, SENSOR_DEVICE_CLASS, SENSOR_EVENT_CODE), v))
|
||||||
|
for k, v in BINARY_SENSORS.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
_UPDATE_MSG = "Updating %s binary sensor"
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
@@ -54,18 +68,19 @@ class AmcrestBinarySensor(BinarySensorDevice):
|
|||||||
|
|
||||||
def __init__(self, name, device, sensor_type):
|
def __init__(self, name, device, sensor_type):
|
||||||
"""Initialize entity."""
|
"""Initialize entity."""
|
||||||
self._name = f"{name} {BINARY_SENSORS[sensor_type][0]}"
|
self._name = f"{name} {BINARY_SENSORS[sensor_type][SENSOR_NAME]}"
|
||||||
self._signal_name = name
|
self._signal_name = name
|
||||||
self._api = device.api
|
self._api = device.api
|
||||||
self._sensor_type = sensor_type
|
self._sensor_type = sensor_type
|
||||||
self._state = None
|
self._state = None
|
||||||
self._device_class = BINARY_SENSORS[sensor_type][1]
|
self._device_class = BINARY_SENSORS[sensor_type][SENSOR_DEVICE_CLASS]
|
||||||
self._unsub_dispatcher = None
|
self._event_code = BINARY_SENSORS[sensor_type][SENSOR_EVENT_CODE]
|
||||||
|
self._unsub_dispatcher = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
"""Return True if entity has to be polled for state."""
|
"""Return True if entity has to be polled for state."""
|
||||||
return self._sensor_type != BINARY_SENSOR_ONLINE
|
return self._sensor_type == BINARY_SENSOR_ONLINE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -89,16 +104,34 @@ class AmcrestBinarySensor(BinarySensorDevice):
|
|||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update entity."""
|
"""Update entity."""
|
||||||
|
if self._sensor_type == BINARY_SENSOR_ONLINE:
|
||||||
|
self._update_online()
|
||||||
|
else:
|
||||||
|
self._update_others()
|
||||||
|
|
||||||
|
def _update_online(self):
|
||||||
|
if not (self._api.available or self.is_on):
|
||||||
|
return
|
||||||
|
_LOGGER.debug(_UPDATE_MSG, self._name)
|
||||||
|
if self._api.available:
|
||||||
|
# Send a command to the camera to test if we can still communicate with it.
|
||||||
|
# Override of Http.command() in __init__.py will set self._api.available
|
||||||
|
# accordingly.
|
||||||
|
try:
|
||||||
|
self._api.current_time
|
||||||
|
except AmcrestError:
|
||||||
|
pass
|
||||||
|
self._state = self._api.available
|
||||||
|
|
||||||
|
def _update_others(self):
|
||||||
if not self.available:
|
if not self.available:
|
||||||
return
|
return
|
||||||
_LOGGER.debug("Updating %s binary sensor", self._name)
|
_LOGGER.debug(_UPDATE_MSG, self._name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self._sensor_type == BINARY_SENSOR_MOTION_DETECTED:
|
self._state = "channels" in self._api.event_channels_happened(
|
||||||
self._state = self._api.is_motion_detected
|
self._event_code
|
||||||
|
)
|
||||||
elif self._sensor_type == BINARY_SENSOR_ONLINE:
|
|
||||||
self._state = self._api.available
|
|
||||||
except AmcrestError as error:
|
except AmcrestError as error:
|
||||||
log_update_error(_LOGGER, "update", self.name, "binary sensor", error)
|
log_update_error(_LOGGER, "update", self.name, "binary sensor", error)
|
||||||
|
|
||||||
@@ -106,14 +139,32 @@ class AmcrestBinarySensor(BinarySensorDevice):
|
|||||||
"""Update state."""
|
"""Update state."""
|
||||||
self.async_schedule_update_ha_state(True)
|
self.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_event_received(self, start):
|
||||||
|
"""Update state from received event."""
|
||||||
|
_LOGGER.debug(_UPDATE_MSG, self._name)
|
||||||
|
self._state = start
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Subscribe to update signal."""
|
"""Subscribe to signals."""
|
||||||
self._unsub_dispatcher = async_dispatcher_connect(
|
self._unsub_dispatcher.append(
|
||||||
self.hass,
|
async_dispatcher_connect(
|
||||||
service_signal(SERVICE_UPDATE, self._signal_name),
|
self.hass,
|
||||||
self.async_on_demand_update,
|
service_signal(SERVICE_UPDATE, self._signal_name),
|
||||||
|
self.async_on_demand_update,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
if self._event_code:
|
||||||
|
self._unsub_dispatcher.append(
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass,
|
||||||
|
service_signal(SERVICE_EVENT, self._signal_name, self._event_code),
|
||||||
|
self.async_event_received,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self):
|
async def async_will_remove_from_hass(self):
|
||||||
"""Disconnect from update signal."""
|
"""Disconnect from update signal."""
|
||||||
self._unsub_dispatcher()
|
for unsub_dispatcher in self._unsub_dispatcher:
|
||||||
|
unsub_dispatcher()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user