HAP-python 5.0.0__tar.gz → 5.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hap_python-5.0.0 → hap_python-5.2.0}/HAP_python.egg-info/PKG-INFO +8 -4
- {hap_python-5.0.0 → hap_python-5.2.0}/HAP_python.egg-info/SOURCES.txt +13 -2
- {hap_python-5.0.0 → hap_python-5.2.0}/HAP_python.egg-info/requires.txt +7 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/PKG-INFO +8 -4
- {hap_python-5.0.0 → hap_python-5.2.0}/README.md +1 -1
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/accessory.py +103 -48
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/accessory_driver.py +300 -137
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/camera.py +666 -44
- hap_python-5.2.0/pyhap/camera_talkback.py +219 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/characteristic.py +87 -36
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/const.py +1 -1
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/encoder.py +18 -4
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hap_crypto.py +38 -28
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hap_event.py +4 -6
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hap_handler.py +125 -75
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hap_protocol.py +173 -53
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hap_server.py +24 -16
- hap_python-5.2.0/pyhap/hds.py +211 -0
- hap_python-5.2.0/pyhap/hds_protocol.py +313 -0
- hap_python-5.2.0/pyhap/hds_recording.py +357 -0
- hap_python-5.2.0/pyhap/hds_server.py +409 -0
- hap_python-5.2.0/pyhap/hksv_recording.py +364 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/hsrp.py +50 -23
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/iid_manager.py +8 -8
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/loader.py +17 -16
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/params.py +8 -1
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/resources/characteristics.json +141 -2
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/resources/services.json +51 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/service.py +27 -19
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/state.py +14 -11
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/tlv.py +40 -9
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/util.py +49 -42
- hap_python-5.2.0/pyproject.toml +157 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/setup.cfg +0 -3
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_accessory.py +51 -39
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_accessory_driver.py +297 -71
- hap_python-5.2.0/tests/test_camera.py +422 -0
- hap_python-5.2.0/tests/test_camera_talkback.py +26 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_characteristic.py +48 -37
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_encoder.py +3 -3
- hap_python-5.2.0/tests/test_fmp4_packets.py +228 -0
- hap_python-5.2.0/tests/test_hap_crypto.py +111 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_hap_handler.py +192 -38
- hap_python-5.2.0/tests/test_hap_protocol.py +1272 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_hap_server.py +22 -12
- hap_python-5.2.0/tests/test_hds_recording.py +668 -0
- hap_python-5.2.0/tests/test_hksv_gating.py +357 -0
- hap_python-5.2.0/tests/test_hksv_recording.py +463 -0
- hap_python-5.2.0/tests/test_hksv_state.py +489 -0
- hap_python-5.2.0/tests/test_hksv_transport.py +446 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_hsrp.py +60 -22
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_iid_manager.py +7 -7
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_loader.py +5 -5
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_service.py +15 -14
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_state.py +15 -13
- hap_python-5.2.0/tests/test_tlv.py +46 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/tests/test_util.py +7 -7
- hap_python-5.0.0/MANIFEST.in +0 -1
- hap_python-5.0.0/pyproject.toml +0 -167
- hap_python-5.0.0/tests/test_camera.py +0 -145
- hap_python-5.0.0/tests/test_hap_crypto.py +0 -32
- hap_python-5.0.0/tests/test_hap_protocol.py +0 -798
- hap_python-5.0.0/tests/test_tlv.py +0 -29
- {hap_python-5.0.0 → hap_python-5.2.0}/AUTHORS +0 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/HAP_python.egg-info/dependency_links.txt +0 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/HAP_python.egg-info/top_level.txt +0 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/LICENSE +0 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/__init__.py +0 -0
- {hap_python-5.0.0 → hap_python-5.2.0}/pyhap/resources/snapshot.jpg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: HAP-python
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2.0
|
|
4
4
|
Summary: HomeKit Accessory Protocol implementation in python
|
|
5
5
|
Author: Ivan Kalchev
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -12,14 +12,13 @@ Classifier: Intended Audience :: Developers
|
|
|
12
12
|
Classifier: Intended Audience :: End Users/Desktop
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Topic :: Home Automation
|
|
21
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.10
|
|
23
22
|
Description-Content-Type: text/markdown
|
|
24
23
|
License-File: LICENSE
|
|
25
24
|
License-File: AUTHORS
|
|
@@ -32,9 +31,14 @@ Requires-Dist: h11
|
|
|
32
31
|
Provides-Extra: qrcode
|
|
33
32
|
Requires-Dist: base36; extra == "qrcode"
|
|
34
33
|
Requires-Dist: pyqrcode; extra == "qrcode"
|
|
34
|
+
Provides-Extra: talkback
|
|
35
|
+
Requires-Dist: pylibsrtp; extra == "talkback"
|
|
36
|
+
Provides-Extra: bench
|
|
37
|
+
Requires-Dist: psutil; extra == "bench"
|
|
38
|
+
Requires-Dist: py-spy; extra == "bench"
|
|
35
39
|
Dynamic: license-file
|
|
36
40
|
|
|
37
|
-
[](https://badge.fury.io/py/HAP-python) [](https://badge.fury.io/py/HAP-python) [](https://github.com/ikalchev/HAP-python/actions/workflows/ci.yaml) [](https://codecov.io/gh/ikalchev/HAP-python) [](https://pypi.python.org/pypi/HAP-python/) [](http://hap-python.readthedocs.io/en/latest/?badge=latest) [](https://pepy.tech/project/hap-python)
|
|
38
42
|
# HAP-python
|
|
39
43
|
|
|
40
44
|
HomeKit Accessory Protocol implementation in python 3.
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
AUTHORS
|
|
2
2
|
LICENSE
|
|
3
|
-
MANIFEST.in
|
|
4
3
|
README.md
|
|
5
4
|
pyproject.toml
|
|
6
|
-
setup.cfg
|
|
7
5
|
HAP_python.egg-info/PKG-INFO
|
|
8
6
|
HAP_python.egg-info/SOURCES.txt
|
|
9
7
|
HAP_python.egg-info/dependency_links.txt
|
|
@@ -13,6 +11,7 @@ pyhap/__init__.py
|
|
|
13
11
|
pyhap/accessory.py
|
|
14
12
|
pyhap/accessory_driver.py
|
|
15
13
|
pyhap/camera.py
|
|
14
|
+
pyhap/camera_talkback.py
|
|
16
15
|
pyhap/characteristic.py
|
|
17
16
|
pyhap/const.py
|
|
18
17
|
pyhap/encoder.py
|
|
@@ -21,6 +20,11 @@ pyhap/hap_event.py
|
|
|
21
20
|
pyhap/hap_handler.py
|
|
22
21
|
pyhap/hap_protocol.py
|
|
23
22
|
pyhap/hap_server.py
|
|
23
|
+
pyhap/hds.py
|
|
24
|
+
pyhap/hds_protocol.py
|
|
25
|
+
pyhap/hds_recording.py
|
|
26
|
+
pyhap/hds_server.py
|
|
27
|
+
pyhap/hksv_recording.py
|
|
24
28
|
pyhap/hsrp.py
|
|
25
29
|
pyhap/iid_manager.py
|
|
26
30
|
pyhap/loader.py
|
|
@@ -35,12 +39,19 @@ pyhap/resources/snapshot.jpg
|
|
|
35
39
|
tests/test_accessory.py
|
|
36
40
|
tests/test_accessory_driver.py
|
|
37
41
|
tests/test_camera.py
|
|
42
|
+
tests/test_camera_talkback.py
|
|
38
43
|
tests/test_characteristic.py
|
|
39
44
|
tests/test_encoder.py
|
|
45
|
+
tests/test_fmp4_packets.py
|
|
40
46
|
tests/test_hap_crypto.py
|
|
41
47
|
tests/test_hap_handler.py
|
|
42
48
|
tests/test_hap_protocol.py
|
|
43
49
|
tests/test_hap_server.py
|
|
50
|
+
tests/test_hds_recording.py
|
|
51
|
+
tests/test_hksv_gating.py
|
|
52
|
+
tests/test_hksv_recording.py
|
|
53
|
+
tests/test_hksv_state.py
|
|
54
|
+
tests/test_hksv_transport.py
|
|
44
55
|
tests/test_hsrp.py
|
|
45
56
|
tests/test_iid_manager.py
|
|
46
57
|
tests/test_loader.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: HAP-python
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2.0
|
|
4
4
|
Summary: HomeKit Accessory Protocol implementation in python
|
|
5
5
|
Author: Ivan Kalchev
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -12,14 +12,13 @@ Classifier: Intended Audience :: Developers
|
|
|
12
12
|
Classifier: Intended Audience :: End Users/Desktop
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Topic :: Home Automation
|
|
21
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.10
|
|
23
22
|
Description-Content-Type: text/markdown
|
|
24
23
|
License-File: LICENSE
|
|
25
24
|
License-File: AUTHORS
|
|
@@ -32,9 +31,14 @@ Requires-Dist: h11
|
|
|
32
31
|
Provides-Extra: qrcode
|
|
33
32
|
Requires-Dist: base36; extra == "qrcode"
|
|
34
33
|
Requires-Dist: pyqrcode; extra == "qrcode"
|
|
34
|
+
Provides-Extra: talkback
|
|
35
|
+
Requires-Dist: pylibsrtp; extra == "talkback"
|
|
36
|
+
Provides-Extra: bench
|
|
37
|
+
Requires-Dist: psutil; extra == "bench"
|
|
38
|
+
Requires-Dist: py-spy; extra == "bench"
|
|
35
39
|
Dynamic: license-file
|
|
36
40
|
|
|
37
|
-
[](https://badge.fury.io/py/HAP-python) [](https://badge.fury.io/py/HAP-python) [](https://github.com/ikalchev/HAP-python/actions/workflows/ci.yaml) [](https://codecov.io/gh/ikalchev/HAP-python) [](https://pypi.python.org/pypi/HAP-python/) [](http://hap-python.readthedocs.io/en/latest/?badge=latest) [](https://pepy.tech/project/hap-python)
|
|
38
42
|
# HAP-python
|
|
39
43
|
|
|
40
44
|
HomeKit Accessory Protocol implementation in python 3.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://badge.fury.io/py/HAP-python) [](https://badge.fury.io/py/HAP-python) [](https://github.com/ikalchev/HAP-python/actions/workflows/ci.yaml) [](https://codecov.io/gh/ikalchev/HAP-python) [](https://pypi.python.org/pypi/HAP-python/) [](http://hap-python.readthedocs.io/en/latest/?badge=latest) [](https://pepy.tech/project/hap-python)
|
|
2
2
|
# HAP-python
|
|
3
3
|
|
|
4
4
|
HomeKit Accessory Protocol implementation in python 3.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"""Module for the Accessory classes."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable, Iterable
|
|
3
4
|
import itertools
|
|
4
5
|
import logging
|
|
5
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
6
7
|
from uuid import UUID
|
|
7
8
|
|
|
8
9
|
from . import SUPPORT_QR_CODE, util
|
|
10
|
+
from .characteristic import Characteristic
|
|
9
11
|
from .const import (
|
|
10
12
|
CATEGORY_BRIDGE,
|
|
11
13
|
CATEGORY_OTHER,
|
|
@@ -26,7 +28,6 @@ if SUPPORT_QR_CODE:
|
|
|
26
28
|
|
|
27
29
|
if TYPE_CHECKING:
|
|
28
30
|
from .accessory_driver import AccessoryDriver
|
|
29
|
-
from .characteristic import Characteristic
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
HAP_PROTOCOL_INFORMATION_SERVICE_UUID = UUID("000000A2-0000-1000-8000-0026BB765291")
|
|
@@ -45,9 +46,9 @@ class Accessory:
|
|
|
45
46
|
def __init__(
|
|
46
47
|
self,
|
|
47
48
|
driver: "AccessoryDriver",
|
|
48
|
-
display_name:
|
|
49
|
-
aid:
|
|
50
|
-
iid_manager:
|
|
49
|
+
display_name: str | None,
|
|
50
|
+
aid: int | None = None,
|
|
51
|
+
iid_manager: IIDManager | None = None,
|
|
51
52
|
) -> None:
|
|
52
53
|
"""Initialise with the given properties.
|
|
53
54
|
|
|
@@ -60,12 +61,12 @@ class Accessory:
|
|
|
60
61
|
will assign the standalone AID to this `Accessory`.
|
|
61
62
|
:type aid: int
|
|
62
63
|
"""
|
|
63
|
-
self.aid:
|
|
64
|
-
self.display_name:
|
|
64
|
+
self.aid: int | None = aid
|
|
65
|
+
self.display_name: str | None = display_name
|
|
65
66
|
self.driver = driver
|
|
66
|
-
self.services:
|
|
67
|
+
self.services: list[Service] = []
|
|
67
68
|
self.iid_manager = iid_manager or IIDManager()
|
|
68
|
-
self.setter_callback:
|
|
69
|
+
self.setter_callback: Callable[[Any], None] | None = None
|
|
69
70
|
|
|
70
71
|
self.add_info_service()
|
|
71
72
|
if aid == STANDALONE_AID:
|
|
@@ -99,7 +100,7 @@ class Accessory:
|
|
|
99
100
|
serv_info.configure_char("SerialNumber", value="default")
|
|
100
101
|
self.add_service(serv_info)
|
|
101
102
|
|
|
102
|
-
def add_protocol_version_service(self):
|
|
103
|
+
def add_protocol_version_service(self) -> None:
|
|
103
104
|
"""Helper method to add the required HAP Protocol Information service"""
|
|
104
105
|
serv_hap_proto_info = Service(
|
|
105
106
|
HAP_PROTOCOL_INFORMATION_SERVICE_UUID, "HAPProtocolInformation"
|
|
@@ -109,10 +110,15 @@ class Accessory:
|
|
|
109
110
|
self.add_service(serv_hap_proto_info)
|
|
110
111
|
|
|
111
112
|
def set_info_service(
|
|
112
|
-
self,
|
|
113
|
-
|
|
113
|
+
self,
|
|
114
|
+
firmware_revision: str | None = None,
|
|
115
|
+
manufacturer: str | None = None,
|
|
116
|
+
model: str | None = None,
|
|
117
|
+
serial_number: str | None = None,
|
|
118
|
+
) -> None:
|
|
114
119
|
"""Quick assign basic accessory information."""
|
|
115
120
|
serv_info = self.get_service("AccessoryInformation")
|
|
121
|
+
assert serv_info is not None # noqa: S101
|
|
116
122
|
if firmware_revision:
|
|
117
123
|
serv_info.configure_char("FirmwareRevision", value=firmware_revision)
|
|
118
124
|
if manufacturer:
|
|
@@ -131,21 +137,21 @@ class Accessory:
|
|
|
131
137
|
|
|
132
138
|
def add_preload_service(
|
|
133
139
|
self,
|
|
134
|
-
service:
|
|
135
|
-
chars:
|
|
136
|
-
unique_id:
|
|
140
|
+
service: str,
|
|
141
|
+
chars: str | Iterable[str] | None = None,
|
|
142
|
+
unique_id: str | int | None = None,
|
|
137
143
|
) -> Service:
|
|
138
144
|
"""Create a service with the given name and add it to this acc."""
|
|
139
|
-
|
|
145
|
+
serv: Service = self.driver.loader.get_service(service)
|
|
140
146
|
if unique_id is not None:
|
|
141
|
-
|
|
147
|
+
serv.unique_id = unique_id
|
|
142
148
|
if chars:
|
|
143
|
-
|
|
144
|
-
for char_name in
|
|
149
|
+
char_names = [chars] if isinstance(chars, str) else chars
|
|
150
|
+
for char_name in char_names:
|
|
145
151
|
char = self.driver.loader.get_char(char_name)
|
|
146
|
-
|
|
147
|
-
self.add_service(
|
|
148
|
-
return
|
|
152
|
+
serv.add_characteristic(char)
|
|
153
|
+
self.add_service(serv)
|
|
154
|
+
return serv
|
|
149
155
|
|
|
150
156
|
def set_primary_service(self, primary_service: Service) -> None:
|
|
151
157
|
"""Set the primary service of the acc."""
|
|
@@ -157,8 +163,8 @@ class Accessory:
|
|
|
157
163
|
|
|
158
164
|
This also assigns unique IIDS to the services and their Characteristics.
|
|
159
165
|
|
|
160
|
-
.. note:: Do not add or remove characteristics from services that have
|
|
161
|
-
to an Accessory, as this will lead to inconsistent IIDs.
|
|
166
|
+
.. note:: Do not add or remove characteristics from services that have
|
|
167
|
+
been added to an Accessory, as this will lead to inconsistent IIDs.
|
|
162
168
|
|
|
163
169
|
:param servs: Variable number of services to add to this Accessory.
|
|
164
170
|
:type: Service
|
|
@@ -171,7 +177,7 @@ class Accessory:
|
|
|
171
177
|
c.broker = self
|
|
172
178
|
self.iid_manager.assign(c)
|
|
173
179
|
|
|
174
|
-
def get_service(self, name: str) ->
|
|
180
|
+
def get_service(self, name: str) -> Service | None:
|
|
175
181
|
"""Return a Service with the given name.
|
|
176
182
|
|
|
177
183
|
A single Service is returned even if more than one Service with the same name
|
|
@@ -208,13 +214,12 @@ class Accessory:
|
|
|
208
214
|
int(self.driver.state.pincode.replace(b"-", b""), 10) & 0x7FFFFFFF
|
|
209
215
|
) # pincode
|
|
210
216
|
|
|
211
|
-
|
|
212
|
-
encoded_payload = base36.dumps(payload).upper()
|
|
217
|
+
encoded_payload: str = base36.dumps(payload).upper()
|
|
213
218
|
encoded_payload = encoded_payload.rjust(9, "0")
|
|
214
219
|
|
|
215
220
|
return "X-HM://" + encoded_payload + self.driver.state.setup_id
|
|
216
221
|
|
|
217
|
-
def get_characteristic(self, aid: int, iid: int) ->
|
|
222
|
+
def get_characteristic(self, aid: int, iid: int) -> "Characteristic | None":
|
|
218
223
|
"""Get the characteristic for the given IID.
|
|
219
224
|
|
|
220
225
|
The AID is used to verify if the search is in the correct accessory.
|
|
@@ -222,9 +227,10 @@ class Accessory:
|
|
|
222
227
|
if aid != self.aid:
|
|
223
228
|
return None
|
|
224
229
|
|
|
225
|
-
|
|
230
|
+
obj = self.iid_manager.get_obj(iid)
|
|
231
|
+
return obj if isinstance(obj, Characteristic) else None
|
|
226
232
|
|
|
227
|
-
def to_HAP(self, include_value: bool = True) ->
|
|
233
|
+
def to_HAP(self, include_value: bool = True) -> dict[str, Any]:
|
|
228
234
|
"""A HAP representation of this Accessory.
|
|
229
235
|
|
|
230
236
|
:return: A HAP representation of this accessory. For example:
|
|
@@ -248,7 +254,7 @@ class Accessory:
|
|
|
248
254
|
],
|
|
249
255
|
}
|
|
250
256
|
|
|
251
|
-
def setup_message(self):
|
|
257
|
+
def setup_message(self) -> None:
|
|
252
258
|
"""Print setup message to console.
|
|
253
259
|
|
|
254
260
|
For QRCode `base36`, `pyqrcode` are required.
|
|
@@ -277,7 +283,9 @@ class Accessory:
|
|
|
277
283
|
)
|
|
278
284
|
|
|
279
285
|
@staticmethod
|
|
280
|
-
def run_at_interval(
|
|
286
|
+
def run_at_interval(
|
|
287
|
+
seconds: float,
|
|
288
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
281
289
|
"""Decorator that runs decorated method every x seconds, until stopped.
|
|
282
290
|
|
|
283
291
|
Can be used with normal and async methods.
|
|
@@ -293,8 +301,8 @@ class Accessory:
|
|
|
293
301
|
:type seconds: float
|
|
294
302
|
"""
|
|
295
303
|
|
|
296
|
-
def _repeat(func):
|
|
297
|
-
async def _wrapper(self, *args):
|
|
304
|
+
def _repeat(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
305
|
+
async def _wrapper(self: Any, *args: Any) -> None:
|
|
298
306
|
while True:
|
|
299
307
|
await self.driver.async_add_job(func, self, *args)
|
|
300
308
|
if await util.event_wait(self.driver.aio_stop_event, seconds):
|
|
@@ -304,22 +312,43 @@ class Accessory:
|
|
|
304
312
|
|
|
305
313
|
return _repeat
|
|
306
314
|
|
|
307
|
-
async def run(self):
|
|
315
|
+
async def run(self) -> None:
|
|
308
316
|
"""Called when the Accessory should start doing its thing.
|
|
309
317
|
|
|
310
318
|
Called when HAP server is running, advertising is set, etc.
|
|
311
319
|
Can be overridden with a normal or async method.
|
|
312
320
|
"""
|
|
313
321
|
|
|
314
|
-
async def stop(self):
|
|
315
|
-
"""Called when the Accessory should stop what is doing and clean up
|
|
322
|
+
async def stop(self) -> None:
|
|
323
|
+
"""Called when the Accessory should stop what it is doing and clean up
|
|
324
|
+
any resources.
|
|
316
325
|
|
|
317
326
|
Can be overridden with a normal or async method.
|
|
318
327
|
"""
|
|
319
328
|
|
|
329
|
+
def restore_accessory_state(self) -> None:
|
|
330
|
+
"""Apply this accessory's entry of ``driver.state.accessory_states``.
|
|
331
|
+
|
|
332
|
+
The driver calls this after it loads its state file, for accessories
|
|
333
|
+
built before that. Does nothing by default.
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
def reset_accessory_state(self) -> None:
|
|
337
|
+
"""Forget settings made by the previous home.
|
|
338
|
+
|
|
339
|
+
The driver calls this when the last pairing is removed. Does nothing by
|
|
340
|
+
default.
|
|
341
|
+
"""
|
|
342
|
+
|
|
320
343
|
# Driver
|
|
321
344
|
|
|
322
|
-
def publish(
|
|
345
|
+
def publish(
|
|
346
|
+
self,
|
|
347
|
+
value: Any,
|
|
348
|
+
sender: Service | Characteristic,
|
|
349
|
+
sender_client_addr: Any = None,
|
|
350
|
+
immediate: bool = False,
|
|
351
|
+
) -> None:
|
|
323
352
|
"""Append AID and IID of the sender and forward it to the driver.
|
|
324
353
|
|
|
325
354
|
Characteristics call this method to send updates.
|
|
@@ -349,13 +378,13 @@ class Bridge(Accessory):
|
|
|
349
378
|
def __init__(
|
|
350
379
|
self,
|
|
351
380
|
driver: "AccessoryDriver",
|
|
352
|
-
display_name:
|
|
353
|
-
iid_manager:
|
|
381
|
+
display_name: str | None,
|
|
382
|
+
iid_manager: IIDManager | None = None,
|
|
354
383
|
) -> None:
|
|
355
384
|
super().__init__(
|
|
356
385
|
driver, display_name, aid=STANDALONE_AID, iid_manager=iid_manager
|
|
357
386
|
)
|
|
358
|
-
self.accessories = {} # aid: acc
|
|
387
|
+
self.accessories: dict[int, Accessory] = {} # aid: acc
|
|
359
388
|
|
|
360
389
|
def add_accessory(self, acc: "Accessory") -> None:
|
|
361
390
|
"""Add the given ``Accessory`` to this ``Bridge``.
|
|
@@ -364,16 +393,17 @@ class Bridge(Accessory):
|
|
|
364
393
|
unique among all the ``Accessories`` in the same `Bridge`. If the given
|
|
365
394
|
``Accessory``'s AID is None, a unique AID will be assigned to it. Otherwise,
|
|
366
395
|
it will be verified that the AID is not the standalone aid (``STANDALONE_AID``)
|
|
367
|
-
and that there is no other ``Accessory`` already in this ``Bridge``
|
|
396
|
+
and that there is no other ``Accessory`` already in this ``Bridge``
|
|
397
|
+
with that AID.
|
|
368
398
|
|
|
369
399
|
.. note:: A ``Bridge`` cannot be added to another ``Bridge``.
|
|
370
400
|
|
|
371
401
|
:param acc: The ``Accessory`` to be bridged.
|
|
372
402
|
:type acc: Accessory
|
|
373
403
|
|
|
374
|
-
:raise ValueError: When the given ``Accessory`` is of category
|
|
375
|
-
or if the AID of the ``Accessory`` clashes with
|
|
376
|
-
``Bridge``.
|
|
404
|
+
:raise ValueError: When the given ``Accessory`` is of category
|
|
405
|
+
``CATEGORY_BRIDGE`` or if the AID of the ``Accessory`` clashes with
|
|
406
|
+
another ``Accessory`` already in this ``Bridge``.
|
|
377
407
|
"""
|
|
378
408
|
if acc.category == CATEGORY_BRIDGE:
|
|
379
409
|
raise ValueError("Bridges cannot be bridged")
|
|
@@ -390,7 +420,11 @@ class Bridge(Accessory):
|
|
|
390
420
|
|
|
391
421
|
self.accessories[acc.aid] = acc
|
|
392
422
|
|
|
393
|
-
|
|
423
|
+
# A Bridge serializes one HAP dict per bridged accessory, which
|
|
424
|
+
# legitimately widens the parent's single-dict return type.
|
|
425
|
+
def to_HAP( # ty: ignore[invalid-method-override]
|
|
426
|
+
self, include_value: bool = True
|
|
427
|
+
) -> list[dict[str, Any]]:
|
|
394
428
|
"""Returns a HAP representation of itself and all contained accessories.
|
|
395
429
|
|
|
396
430
|
.. seealso:: Accessory.to_HAP
|
|
@@ -400,10 +434,11 @@ class Bridge(Accessory):
|
|
|
400
434
|
for acc in (super(), *self.accessories.values())
|
|
401
435
|
]
|
|
402
436
|
|
|
403
|
-
def get_characteristic(self, aid: int, iid: int) ->
|
|
437
|
+
def get_characteristic(self, aid: int, iid: int) -> "Characteristic | None":
|
|
404
438
|
""".. seealso:: Accessory.to_HAP"""
|
|
405
439
|
if self.aid == aid:
|
|
406
|
-
|
|
440
|
+
obj = self.iid_manager.get_obj(iid)
|
|
441
|
+
return obj if isinstance(obj, Characteristic) else None
|
|
407
442
|
|
|
408
443
|
acc = self.accessories.get(aid)
|
|
409
444
|
if acc is None:
|
|
@@ -411,6 +446,26 @@ class Bridge(Accessory):
|
|
|
411
446
|
|
|
412
447
|
return acc.get_characteristic(aid, iid)
|
|
413
448
|
|
|
449
|
+
def restore_accessory_state(self) -> None:
|
|
450
|
+
"""Restore the state of each bridged accessory."""
|
|
451
|
+
for acc in self.accessories.values():
|
|
452
|
+
try:
|
|
453
|
+
acc.restore_accessory_state()
|
|
454
|
+
except Exception:
|
|
455
|
+
logger.warning(
|
|
456
|
+
"Failed to restore the state of %s", acc.display_name, exc_info=True
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
def reset_accessory_state(self) -> None:
|
|
460
|
+
"""Reset the state of each bridged accessory."""
|
|
461
|
+
for acc in self.accessories.values():
|
|
462
|
+
try:
|
|
463
|
+
acc.reset_accessory_state()
|
|
464
|
+
except Exception:
|
|
465
|
+
logger.warning(
|
|
466
|
+
"Failed to reset the state of %s", acc.display_name, exc_info=True
|
|
467
|
+
)
|
|
468
|
+
|
|
414
469
|
async def run(self) -> None:
|
|
415
470
|
"""Schedule tasks for each of the accessories' run method."""
|
|
416
471
|
for acc in self.accessories.values():
|