axis 60__tar.gz → 61__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.
- {axis-60 → axis-61}/PKG-INFO +3 -3
- {axis-60 → axis-61}/axis/__main__.py +1 -1
- {axis-60 → axis-61}/axis/errors.py +7 -2
- {axis-60 → axis-61}/axis/interfaces/api_handler.py +1 -2
- {axis-60 → axis-61}/axis/interfaces/applications/motion_guard.py +1 -1
- {axis-60 → axis-61}/axis/interfaces/light_control.py +35 -45
- {axis-60 → axis-61}/axis/interfaces/port_management.py +1 -1
- {axis-60 → axis-61}/axis/interfaces/vapix.py +10 -7
- {axis-60 → axis-61}/axis/interfaces/view_areas.py +1 -1
- {axis-60 → axis-61}/axis/models/mqtt.py +2 -2
- {axis-60 → axis-61}/axis/models/parameters/properties.py +2 -2
- {axis-60 → axis-61}/axis/rtsp.py +19 -19
- {axis-60 → axis-61}/axis/stream_manager.py +2 -1
- {axis-60 → axis-61}/axis.egg-info/PKG-INFO +3 -3
- {axis-60 → axis-61}/axis.egg-info/requires.txt +1 -1
- {axis-60 → axis-61}/pyproject.toml +51 -33
- {axis-60 → axis-61}/tests/test_light_control.py +25 -25
- {axis-60 → axis-61}/tests/test_user_groups.py +6 -3
- {axis-60 → axis-61}/tests/test_vapix.py +4 -2
- {axis-60 → axis-61}/LICENSE +0 -0
- {axis-60 → axis-61}/README.md +0 -0
- {axis-60 → axis-61}/axis/__init__.py +0 -0
- {axis-60 → axis-61}/axis/device.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/__init__.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/api_discovery.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/__init__.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/application_handler.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/applications.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/fence_guard.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/loitering_guard.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/object_analytics.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/applications/vmd4.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/basic_device_info.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/event_instances.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/event_manager.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/mqtt.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/__init__.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/brand.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/image.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/io_port.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/param_cgi.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/param_handler.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/properties.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/ptz.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/parameters/stream_profile.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/pir_sensor_configuration.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/port_cgi.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/ptz.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/pwdgrp_cgi.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/stream_profiles.py +0 -0
- {axis-60 → axis-61}/axis/interfaces/user_groups.py +0 -0
- {axis-60 → axis-61}/axis/models/__init__.py +0 -0
- {axis-60 → axis-61}/axis/models/api.py +0 -0
- {axis-60 → axis-61}/axis/models/api_discovery.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/__init__.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/application.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/fence_guard.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/loitering_guard.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/motion_guard.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/object_analytics.py +0 -0
- {axis-60 → axis-61}/axis/models/applications/vmd4.py +0 -0
- {axis-60 → axis-61}/axis/models/basic_device_info.py +0 -0
- {axis-60 → axis-61}/axis/models/configuration.py +0 -0
- {axis-60 → axis-61}/axis/models/event.py +0 -0
- {axis-60 → axis-61}/axis/models/event_instance.py +0 -0
- {axis-60 → axis-61}/axis/models/light_control.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/__init__.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/brand.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/image.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/io_port.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/param_cgi.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/ptz.py +0 -0
- {axis-60 → axis-61}/axis/models/parameters/stream_profile.py +0 -0
- {axis-60 → axis-61}/axis/models/pir_sensor_configuration.py +0 -0
- {axis-60 → axis-61}/axis/models/port_cgi.py +0 -0
- {axis-60 → axis-61}/axis/models/port_management.py +0 -0
- {axis-60 → axis-61}/axis/models/ptz_cgi.py +0 -0
- {axis-60 → axis-61}/axis/models/pwdgrp_cgi.py +0 -0
- {axis-60 → axis-61}/axis/models/stream_profile.py +0 -0
- {axis-60 → axis-61}/axis/models/user_group.py +0 -0
- {axis-60 → axis-61}/axis/models/view_area.py +0 -0
- {axis-60 → axis-61}/axis/py.typed +0 -0
- {axis-60 → axis-61}/axis.egg-info/SOURCES.txt +0 -0
- {axis-60 → axis-61}/axis.egg-info/dependency_links.txt +0 -0
- {axis-60 → axis-61}/axis.egg-info/entry_points.txt +0 -0
- {axis-60 → axis-61}/axis.egg-info/top_level.txt +0 -0
- {axis-60 → axis-61}/setup.cfg +0 -0
- {axis-60 → axis-61}/tests/test_api_discovery.py +0 -0
- {axis-60 → axis-61}/tests/test_api_handler.py +0 -0
- {axis-60 → axis-61}/tests/test_basic_device_info.py +0 -0
- {axis-60 → axis-61}/tests/test_configuration.py +0 -0
- {axis-60 → axis-61}/tests/test_device.py +0 -0
- {axis-60 → axis-61}/tests/test_event.py +0 -0
- {axis-60 → axis-61}/tests/test_event_instances.py +0 -0
- {axis-60 → axis-61}/tests/test_event_stream.py +0 -0
- {axis-60 → axis-61}/tests/test_mqtt.py +0 -0
- {axis-60 → axis-61}/tests/test_pir_sensor_configuration.py +0 -0
- {axis-60 → axis-61}/tests/test_port_cgi.py +0 -0
- {axis-60 → axis-61}/tests/test_port_management.py +0 -0
- {axis-60 → axis-61}/tests/test_ptz.py +0 -0
- {axis-60 → axis-61}/tests/test_pwdgrp_cgi.py +0 -0
- {axis-60 → axis-61}/tests/test_rtsp.py +0 -0
- {axis-60 → axis-61}/tests/test_stream_manager.py +0 -0
- {axis-60 → axis-61}/tests/test_stream_profiles.py +0 -0
- {axis-60 → axis-61}/tests/test_view_areas.py +0 -0
{axis-60 → axis-61}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: axis
|
|
3
|
-
Version:
|
|
3
|
+
Version: 61
|
|
4
4
|
Summary: A Python library for communicating with devices from Axis Communications
|
|
5
5
|
Author-email: Robert Svensson <Kane610@users.noreply.github.com>
|
|
6
6
|
License: MIT
|
|
@@ -12,9 +12,9 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Topic :: Home Automation
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.12.0
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
Provides-Extra: requirements
|
|
20
20
|
Provides-Extra: requirements_test
|
|
@@ -20,7 +20,7 @@ async def axis_device(
|
|
|
20
20
|
host: str, port: int, username: str, password: str
|
|
21
21
|
) -> axis.device.AxisDevice:
|
|
22
22
|
"""Create a Axis device."""
|
|
23
|
-
session = AsyncClient(verify=False)
|
|
23
|
+
session = AsyncClient(verify=False) # noqa: S501
|
|
24
24
|
device = axis.device.AxisDevice(
|
|
25
25
|
axis.models.configuration.Configuration(
|
|
26
26
|
session, host, port=port, username=username, password=password
|
|
@@ -36,10 +36,15 @@ class PathNotFound(AxisException):
|
|
|
36
36
|
"""Path not found."""
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
ERRORS = {
|
|
39
|
+
ERRORS = {
|
|
40
|
+
401: Unauthorized,
|
|
41
|
+
403: Forbidden,
|
|
42
|
+
404: PathNotFound,
|
|
43
|
+
405: MethodNotAllowed,
|
|
44
|
+
}
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
def raise_error(error: int) -> None:
|
|
43
48
|
"""Raise error."""
|
|
44
49
|
cls = ERRORS.get(error, AxisException)
|
|
45
|
-
raise cls(
|
|
50
|
+
raise cls(error)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""API handler class and base class for an API endpoint."""
|
|
2
2
|
|
|
3
|
-
from abc import ABC
|
|
4
3
|
from collections.abc import (
|
|
5
4
|
Callable,
|
|
6
5
|
ItemsView,
|
|
@@ -26,7 +25,7 @@ UnsubscribeType = Callable[[], None]
|
|
|
26
25
|
ID_FILTER_ALL = "*"
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
class SubscriptionHandler
|
|
28
|
+
class SubscriptionHandler:
|
|
30
29
|
"""Manage subscription and notification to subscribers."""
|
|
31
30
|
|
|
32
31
|
def __init__(self) -> None:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
AXIS Motion Guard is a video motion detection application that detects
|
|
4
4
|
and triggers an alarm whenever an object, such as a person or vehicle,
|
|
5
|
-
moves within predefined areas in a camera
|
|
5
|
+
moves within predefined areas in a camera's field of view.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from ...models.applications.application import ApplicationName
|
|
@@ -67,62 +67,60 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
67
67
|
|
|
68
68
|
async def get_light_information(self) -> dict[str, LightInformation]:
|
|
69
69
|
"""List the light control information."""
|
|
70
|
-
assert isinstance(self.api_version, str)
|
|
71
70
|
bytes_data = await self.vapix.api_request(
|
|
72
|
-
GetLightInformationRequest(api_version=self.
|
|
71
|
+
GetLightInformationRequest(api_version=self.default_api_version)
|
|
73
72
|
)
|
|
74
73
|
return GetLightInformationResponse.decode(bytes_data).data
|
|
75
74
|
|
|
76
75
|
async def get_service_capabilities(self) -> ServiceCapabilities:
|
|
77
76
|
"""List the light control information."""
|
|
78
|
-
assert isinstance(self.api_version, str)
|
|
79
77
|
bytes_data = await self.vapix.api_request(
|
|
80
|
-
GetServiceCapabilitiesRequest(api_version=self.
|
|
78
|
+
GetServiceCapabilitiesRequest(api_version=self.default_api_version)
|
|
81
79
|
)
|
|
82
80
|
return GetServiceCapabilitiesResponse.decode(bytes_data).data
|
|
83
81
|
|
|
84
82
|
async def activate_light(self, light_id: str) -> None:
|
|
85
83
|
"""Activate the light."""
|
|
86
|
-
assert isinstance(self.api_version, str)
|
|
87
84
|
await self.vapix.api_request(
|
|
88
|
-
ActivateLightRequest(
|
|
85
|
+
ActivateLightRequest(
|
|
86
|
+
api_version=self.default_api_version, light_id=light_id
|
|
87
|
+
)
|
|
89
88
|
)
|
|
90
89
|
|
|
91
90
|
async def deactivate_light(self, light_id: str) -> None:
|
|
92
91
|
"""Deactivate the light."""
|
|
93
|
-
assert isinstance(self.api_version, str)
|
|
94
92
|
await self.vapix.api_request(
|
|
95
|
-
DeactivateLightRequest(
|
|
93
|
+
DeactivateLightRequest(
|
|
94
|
+
api_version=self.default_api_version, light_id=light_id
|
|
95
|
+
)
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
async def enable_light(self, light_id: str) -> None:
|
|
99
99
|
"""Activate the light."""
|
|
100
|
-
assert isinstance(self.api_version, str)
|
|
101
100
|
await self.vapix.api_request(
|
|
102
|
-
EnableLightRequest(api_version=self.
|
|
101
|
+
EnableLightRequest(api_version=self.default_api_version, light_id=light_id)
|
|
103
102
|
)
|
|
104
103
|
|
|
105
104
|
async def disable_light(self, light_id: str) -> None:
|
|
106
105
|
"""Deactivate the light."""
|
|
107
|
-
assert isinstance(self.api_version, str)
|
|
108
106
|
await self.vapix.api_request(
|
|
109
|
-
DisableLightRequest(api_version=self.
|
|
107
|
+
DisableLightRequest(api_version=self.default_api_version, light_id=light_id)
|
|
110
108
|
)
|
|
111
109
|
|
|
112
110
|
async def get_light_status(self, light_id: str) -> bool:
|
|
113
111
|
"""Get light status if its on or off."""
|
|
114
|
-
assert isinstance(self.api_version, str)
|
|
115
112
|
bytes_data = await self.vapix.api_request(
|
|
116
|
-
GetLightStatusRequest(
|
|
113
|
+
GetLightStatusRequest(
|
|
114
|
+
api_version=self.default_api_version, light_id=light_id
|
|
115
|
+
)
|
|
117
116
|
)
|
|
118
117
|
return GetLightStatusResponse.decode(bytes_data).data
|
|
119
118
|
|
|
120
119
|
async def set_automatic_intensity_mode(self, light_id: str, enabled: bool) -> None:
|
|
121
120
|
"""Enable the automatic light intensity control."""
|
|
122
|
-
assert isinstance(self.api_version, str)
|
|
123
121
|
await self.vapix.api_request(
|
|
124
122
|
SetAutomaticIntensityModeRequest(
|
|
125
|
-
api_version=self.
|
|
123
|
+
api_version=self.default_api_version,
|
|
126
124
|
light_id=light_id,
|
|
127
125
|
enabled=enabled,
|
|
128
126
|
)
|
|
@@ -130,18 +128,18 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
130
128
|
|
|
131
129
|
async def get_valid_intensity(self, light_id: str) -> Range:
|
|
132
130
|
"""Get valid intensity range for light."""
|
|
133
|
-
assert isinstance(self.api_version, str)
|
|
134
131
|
bytes_data = await self.vapix.api_request(
|
|
135
|
-
GetValidIntensityRequest(
|
|
132
|
+
GetValidIntensityRequest(
|
|
133
|
+
api_version=self.default_api_version, light_id=light_id
|
|
134
|
+
)
|
|
136
135
|
)
|
|
137
136
|
return GetValidIntensityResponse.decode(bytes_data).data
|
|
138
137
|
|
|
139
138
|
async def set_manual_intensity(self, light_id: str, intensity: int) -> None:
|
|
140
139
|
"""Manually sets the intensity."""
|
|
141
|
-
assert isinstance(self.api_version, str)
|
|
142
140
|
await self.vapix.api_request(
|
|
143
141
|
SetManualIntensityRequest(
|
|
144
|
-
api_version=self.
|
|
142
|
+
api_version=self.default_api_version,
|
|
145
143
|
light_id=light_id,
|
|
146
144
|
intensity=intensity,
|
|
147
145
|
)
|
|
@@ -149,9 +147,10 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
149
147
|
|
|
150
148
|
async def get_manual_intensity(self, light_id: str) -> int:
|
|
151
149
|
"""Enable the automatic light intensity control."""
|
|
152
|
-
assert isinstance(self.api_version, str)
|
|
153
150
|
bytes_data = await self.vapix.api_request(
|
|
154
|
-
GetManualIntensityRequest(
|
|
151
|
+
GetManualIntensityRequest(
|
|
152
|
+
api_version=self.default_api_version, light_id=light_id
|
|
153
|
+
)
|
|
155
154
|
)
|
|
156
155
|
return GetManualIntensityResponse.decode(bytes_data).data
|
|
157
156
|
|
|
@@ -159,10 +158,9 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
159
158
|
self, light_id: str, led_id: int, intensity: int
|
|
160
159
|
) -> None:
|
|
161
160
|
"""Manually sets the intensity for an individual LED."""
|
|
162
|
-
assert isinstance(self.api_version, str)
|
|
163
161
|
await self.vapix.api_request(
|
|
164
162
|
SetIndividualIntensityRequest(
|
|
165
|
-
api_version=self.
|
|
163
|
+
api_version=self.default_api_version,
|
|
166
164
|
light_id=light_id,
|
|
167
165
|
led_id=led_id,
|
|
168
166
|
intensity=intensity,
|
|
@@ -171,10 +169,9 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
171
169
|
|
|
172
170
|
async def get_individual_intensity(self, light_id: str, led_id: int) -> int:
|
|
173
171
|
"""Receives the intensity from the setIndividualIntensity request."""
|
|
174
|
-
assert isinstance(self.api_version, str)
|
|
175
172
|
bytes_data = await self.vapix.api_request(
|
|
176
173
|
GetIndividualIntensityRequest(
|
|
177
|
-
api_version=self.
|
|
174
|
+
api_version=self.default_api_version,
|
|
178
175
|
light_id=light_id,
|
|
179
176
|
led_id=led_id,
|
|
180
177
|
)
|
|
@@ -183,9 +180,10 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
183
180
|
|
|
184
181
|
async def get_current_intensity(self, light_id: str) -> int:
|
|
185
182
|
"""Receives the intensity from the setIndividualIntensity request."""
|
|
186
|
-
assert isinstance(self.api_version, str)
|
|
187
183
|
bytes_data = await self.vapix.api_request(
|
|
188
|
-
GetCurrentIntensityRequest(
|
|
184
|
+
GetCurrentIntensityRequest(
|
|
185
|
+
api_version=self.default_api_version, light_id=light_id
|
|
186
|
+
)
|
|
189
187
|
)
|
|
190
188
|
return GetCurrentIntensityResponse.decode(bytes_data).data
|
|
191
189
|
|
|
@@ -195,21 +193,19 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
195
193
|
"""Automatically control the angle of illumination.
|
|
196
194
|
|
|
197
195
|
Using this mode means that the angle of illumination
|
|
198
|
-
is the same as the camera
|
|
196
|
+
is the same as the camera's angle of view.
|
|
199
197
|
"""
|
|
200
|
-
assert isinstance(self.api_version, str)
|
|
201
198
|
await self.vapix.api_request(
|
|
202
199
|
SetAutomaticAngleOfIlluminationModeRequest(
|
|
203
|
-
api_version=self.
|
|
200
|
+
api_version=self.default_api_version, light_id=light_id, enabled=enabled
|
|
204
201
|
)
|
|
205
202
|
)
|
|
206
203
|
|
|
207
204
|
async def get_valid_angle_of_illumination(self, light_id: str) -> list[Range]:
|
|
208
205
|
"""List the valid angle of illumination values."""
|
|
209
|
-
assert isinstance(self.api_version, str)
|
|
210
206
|
bytes_data = await self.vapix.api_request(
|
|
211
207
|
GetValidAngleOfIlluminationRequest(
|
|
212
|
-
api_version=self.
|
|
208
|
+
api_version=self.default_api_version, light_id=light_id
|
|
213
209
|
)
|
|
214
210
|
)
|
|
215
211
|
return GetValidAngleOfIlluminationResponse.decode(bytes_data).data
|
|
@@ -220,12 +216,11 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
220
216
|
"""Set the manual angle of illumination.
|
|
221
217
|
|
|
222
218
|
This is useful when the angle of illumination needs
|
|
223
|
-
to be different from the camera
|
|
219
|
+
to be different from the camera's view angle.
|
|
224
220
|
"""
|
|
225
|
-
assert isinstance(self.api_version, str)
|
|
226
221
|
await self.vapix.api_request(
|
|
227
222
|
SetManualAngleOfIlluminationModeRequest(
|
|
228
|
-
api_version=self.
|
|
223
|
+
api_version=self.default_api_version,
|
|
229
224
|
light_id=light_id,
|
|
230
225
|
angle_of_illumination=angle_of_illumination,
|
|
231
226
|
)
|
|
@@ -233,20 +228,18 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
233
228
|
|
|
234
229
|
async def get_manual_angle_of_illumination(self, light_id: str) -> int:
|
|
235
230
|
"""Get the angle of illumination."""
|
|
236
|
-
assert isinstance(self.api_version, str)
|
|
237
231
|
bytes_data = await self.vapix.api_request(
|
|
238
232
|
GetManualAngleOfIlluminationRequest(
|
|
239
|
-
api_version=self.
|
|
233
|
+
api_version=self.default_api_version, light_id=light_id
|
|
240
234
|
)
|
|
241
235
|
)
|
|
242
236
|
return GetManualAngleOfIlluminationResponse.decode(bytes_data).data
|
|
243
237
|
|
|
244
238
|
async def get_current_angle_of_illumination(self, light_id: str) -> int:
|
|
245
239
|
"""Receive the current angle of illumination."""
|
|
246
|
-
assert isinstance(self.api_version, str)
|
|
247
240
|
bytes_data = await self.vapix.api_request(
|
|
248
241
|
GetCurrentAngleOfIlluminationRequest(
|
|
249
|
-
api_version=self.
|
|
242
|
+
api_version=self.default_api_version, light_id=light_id
|
|
250
243
|
)
|
|
251
244
|
)
|
|
252
245
|
return GetCurrentAngleOfIlluminationResponse.decode(bytes_data).data
|
|
@@ -255,25 +248,22 @@ class LightHandler(ApiHandler[LightInformation]):
|
|
|
255
248
|
self, light_id: str, enabled: bool
|
|
256
249
|
) -> None:
|
|
257
250
|
"""Enable automatic synchronization with the day/night mode."""
|
|
258
|
-
assert isinstance(self.api_version, str)
|
|
259
251
|
await self.vapix.api_request(
|
|
260
252
|
SetLightSynchronizeDayNightModeRequest(
|
|
261
|
-
api_version=self.
|
|
253
|
+
api_version=self.default_api_version, light_id=light_id, enabled=enabled
|
|
262
254
|
)
|
|
263
255
|
)
|
|
264
256
|
|
|
265
257
|
async def get_light_synchronization_day_night_mode(self, light_id: str) -> bool:
|
|
266
258
|
"""Check if the automatic synchronization is enabled with the day/night mode."""
|
|
267
|
-
assert isinstance(self.api_version, str)
|
|
268
259
|
bytes_data = await self.vapix.api_request(
|
|
269
260
|
GetLightSynchronizeDayNightModeRequest(
|
|
270
|
-
api_version=self.
|
|
261
|
+
api_version=self.default_api_version, light_id=light_id
|
|
271
262
|
)
|
|
272
263
|
)
|
|
273
264
|
return GetLightSynchronizeDayNightModeResponse.decode(bytes_data).data
|
|
274
265
|
|
|
275
266
|
async def get_supported_versions(self) -> list[str]:
|
|
276
267
|
"""List supported API versions."""
|
|
277
|
-
assert isinstance(self.api_version, str)
|
|
278
268
|
bytes_data = await self.vapix.api_request(GetSupportedVersionsRequest())
|
|
279
269
|
return GetSupportedVersionsResponse.decode(bytes_data).data
|
|
@@ -45,7 +45,7 @@ class IoPortManagement(ApiHandler[Port]):
|
|
|
45
45
|
* Configuring the states and what constitutes a normal
|
|
46
46
|
and triggered state respectively.
|
|
47
47
|
This will make triggers activate in either open or closed circuits.
|
|
48
|
-
The reason the change is treated as a nice name is because it doesn
|
|
48
|
+
The reason the change is treated as a nice name is because it doesn't
|
|
49
49
|
affect the underlying behavior of the port.
|
|
50
50
|
Devices with configurable ports can change the direction
|
|
51
51
|
to either input or output.
|
|
@@ -9,11 +9,8 @@ from typing import TYPE_CHECKING, Any
|
|
|
9
9
|
import httpx
|
|
10
10
|
|
|
11
11
|
from ..errors import RequestError, raise_error
|
|
12
|
-
from ..models.api import ApiRequest
|
|
13
12
|
from ..models.pwdgrp_cgi import SecondaryGroup
|
|
14
|
-
from ..models.stream_profile import StreamProfile
|
|
15
13
|
from .api_discovery import ApiDiscoveryHandler
|
|
16
|
-
from .api_handler import ApiHandler
|
|
17
14
|
from .applications import (
|
|
18
15
|
ApplicationsHandler,
|
|
19
16
|
)
|
|
@@ -42,6 +39,9 @@ from .view_areas import ViewAreaHandler
|
|
|
42
39
|
|
|
43
40
|
if TYPE_CHECKING:
|
|
44
41
|
from ..device import AxisDevice
|
|
42
|
+
from ..models.api import ApiRequest
|
|
43
|
+
from ..models.stream_profile import StreamProfile
|
|
44
|
+
from .api_handler import ApiHandler
|
|
45
45
|
|
|
46
46
|
LOGGER = logging.getLogger(__name__)
|
|
47
47
|
|
|
@@ -276,16 +276,19 @@ class Vapix:
|
|
|
276
276
|
timeout=TIME_OUT,
|
|
277
277
|
)
|
|
278
278
|
|
|
279
|
-
except httpx.TimeoutException:
|
|
280
|
-
|
|
279
|
+
except httpx.TimeoutException as errt:
|
|
280
|
+
message = "Timeout"
|
|
281
|
+
raise RequestError(message) from errt
|
|
281
282
|
|
|
282
283
|
except httpx.TransportError as errc:
|
|
283
284
|
LOGGER.debug("%s", errc)
|
|
284
|
-
|
|
285
|
+
message = f"Connection error: {errc}"
|
|
286
|
+
raise RequestError(message) from errc
|
|
285
287
|
|
|
286
288
|
except httpx.RequestError as err:
|
|
287
289
|
LOGGER.debug("%s", err)
|
|
288
|
-
|
|
290
|
+
message = f"Unknown error: {err}"
|
|
291
|
+
raise RequestError(message) from err
|
|
289
292
|
|
|
290
293
|
try:
|
|
291
294
|
response.raise_for_status()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""View area API.
|
|
2
2
|
|
|
3
|
-
The View Area API makes it possible to define the subsections of a camera
|
|
3
|
+
The View Area API makes it possible to define the subsections of a camera's full view
|
|
4
4
|
as individual, virtual channels. This means that a wide angle and/or high resolution
|
|
5
5
|
camera can provide multiple video streams at a lower resolution where each stream
|
|
6
6
|
covers a specific region of interest. The API is also able to simplify the installation
|
|
@@ -341,7 +341,7 @@ class ClientConfig:
|
|
|
341
341
|
"""Specifies if a message should be sent when a connection is established.
|
|
342
342
|
|
|
343
343
|
Contains options related to connect announcements.
|
|
344
|
-
If this object is not defined this message won
|
|
344
|
+
If this object is not defined this message won't be sent.
|
|
345
345
|
"""
|
|
346
346
|
connect_timeout: int | None = None
|
|
347
347
|
"""The timed interval (in seconds) to allow a connect to finish.
|
|
@@ -359,7 +359,7 @@ class ClientConfig:
|
|
|
359
359
|
"""Specifies if a message should be sent when the client is manually disconnected.
|
|
360
360
|
|
|
361
361
|
Contains options related to manual disconnect announcements.
|
|
362
|
-
If this object is not defined this message won
|
|
362
|
+
If this object is not defined this message won't be sent.
|
|
363
363
|
This message should not be confused with LWT,
|
|
364
364
|
as it is used when the connection is lost and managed by the broker.
|
|
365
365
|
"""
|
|
@@ -182,8 +182,8 @@ class PropertyParam(ParamItem):
|
|
|
182
182
|
return cls(
|
|
183
183
|
id="properties",
|
|
184
184
|
api_http_version=data["API"]["HTTP"]["Version"],
|
|
185
|
-
api_metadata=data["API"]
|
|
186
|
-
api_metadata_version=data["API"]
|
|
185
|
+
api_metadata=data["API"].get("Metadata", {}).get("Metadata", "no"),
|
|
186
|
+
api_metadata_version=data["API"].get("Metadata", {}).get("Version", "0.0"),
|
|
187
187
|
api_ptz_presets_version=data["API"]
|
|
188
188
|
.get("PTZ", {})
|
|
189
189
|
.get("Presets", {})
|
{axis-60 → axis-61}/axis/rtsp.py
RENAMED
|
@@ -361,11 +361,11 @@ class RTSPSession:
|
|
|
361
361
|
"""RFC 2617."""
|
|
362
362
|
from hashlib import md5
|
|
363
363
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
encrypt_response = f"{
|
|
364
|
+
_ha1 = f"{self.username}:{self.realm}:{self.password}"
|
|
365
|
+
ha1 = md5(_ha1.encode("UTF-8")).hexdigest()
|
|
366
|
+
_ha2 = f"{self.method}:{self.url}"
|
|
367
|
+
ha2 = md5(_ha2.encode("UTF-8")).hexdigest()
|
|
368
|
+
encrypt_response = f"{ha1}:{self.nonce}:{ha2}"
|
|
369
369
|
response = md5(encrypt_response.encode("UTF-8")).hexdigest()
|
|
370
370
|
|
|
371
371
|
digest_auth = "Digest "
|
|
@@ -399,12 +399,12 @@ class RTSPMethods:
|
|
|
399
399
|
"""Define message methods."""
|
|
400
400
|
self.session = session
|
|
401
401
|
self.message_methods: dict[str, Callable[[], str]] = {
|
|
402
|
-
"OPTIONS": self.
|
|
403
|
-
"DESCRIBE": self.
|
|
404
|
-
"SETUP": self.
|
|
405
|
-
"PLAY": self.
|
|
406
|
-
"KEEP-ALIVE": self.
|
|
407
|
-
"TEARDOWN": self.
|
|
402
|
+
"OPTIONS": self.options,
|
|
403
|
+
"DESCRIBE": self.describe,
|
|
404
|
+
"SETUP": self.setup,
|
|
405
|
+
"PLAY": self.play,
|
|
406
|
+
"KEEP-ALIVE": self.keep_alive,
|
|
407
|
+
"TEARDOWN": self.teardown,
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
@property
|
|
@@ -414,11 +414,11 @@ class RTSPMethods:
|
|
|
414
414
|
_LOGGER.debug(message)
|
|
415
415
|
return message
|
|
416
416
|
|
|
417
|
-
def
|
|
417
|
+
def keep_alive(self) -> str:
|
|
418
418
|
"""Keep-Alive messages doesn't need authentication."""
|
|
419
|
-
return self.
|
|
419
|
+
return self.options(False)
|
|
420
420
|
|
|
421
|
-
def
|
|
421
|
+
def options(self, authenticate: bool = True) -> str:
|
|
422
422
|
"""Request options device supports."""
|
|
423
423
|
message = f"OPTIONS {self.session.url} RTSP/1.0\r\n"
|
|
424
424
|
message += self.sequence
|
|
@@ -428,7 +428,7 @@ class RTSPMethods:
|
|
|
428
428
|
message += "\r\n"
|
|
429
429
|
return message
|
|
430
430
|
|
|
431
|
-
def
|
|
431
|
+
def describe(self) -> str:
|
|
432
432
|
"""Request description of what services RTSP server make available."""
|
|
433
433
|
message = f"DESCRIBE {self.session.url} RTSP/1.0\r\n"
|
|
434
434
|
message += self.sequence
|
|
@@ -438,7 +438,7 @@ class RTSPMethods:
|
|
|
438
438
|
message += "\r\n"
|
|
439
439
|
return message
|
|
440
440
|
|
|
441
|
-
def
|
|
441
|
+
def setup(self) -> str:
|
|
442
442
|
"""Set up stream transport."""
|
|
443
443
|
message = f"SETUP {self.session.control_url} RTSP/1.0\r\n"
|
|
444
444
|
message += self.sequence
|
|
@@ -448,7 +448,7 @@ class RTSPMethods:
|
|
|
448
448
|
message += "\r\n"
|
|
449
449
|
return message
|
|
450
450
|
|
|
451
|
-
def
|
|
451
|
+
def play(self) -> str:
|
|
452
452
|
"""RTSP session is ready to send data."""
|
|
453
453
|
message = f"PLAY {self.session.url} RTSP/1.0\r\n"
|
|
454
454
|
message += self.sequence
|
|
@@ -458,7 +458,7 @@ class RTSPMethods:
|
|
|
458
458
|
message += "\r\n"
|
|
459
459
|
return message
|
|
460
460
|
|
|
461
|
-
def
|
|
461
|
+
def teardown(self) -> str:
|
|
462
462
|
"""Tell device to tear down session."""
|
|
463
463
|
message = f"TEARDOWN {self.session.url} RTSP/1.0\r\n"
|
|
464
464
|
message += self.sequence
|
|
@@ -471,7 +471,7 @@ class RTSPMethods:
|
|
|
471
471
|
@property
|
|
472
472
|
def sequence(self) -> str:
|
|
473
473
|
"""Generate sequence string."""
|
|
474
|
-
return f"CSeq: {
|
|
474
|
+
return f"CSeq: {self.session.sequence}\r\n"
|
|
475
475
|
|
|
476
476
|
@property
|
|
477
477
|
def authentication(self) -> str:
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"""Python library to enable Axis devices to integrate with Home Assistant."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from collections.abc import Callable
|
|
5
4
|
import logging
|
|
6
5
|
from typing import TYPE_CHECKING
|
|
7
6
|
|
|
8
7
|
from .rtsp import RTSPClient, Signal, State
|
|
9
8
|
|
|
10
9
|
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
|
|
11
12
|
from .device import AxisDevice
|
|
12
13
|
|
|
13
14
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: axis
|
|
3
|
-
Version:
|
|
3
|
+
Version: 61
|
|
4
4
|
Summary: A Python library for communicating with devices from Axis Communications
|
|
5
5
|
Author-email: Robert Svensson <Kane610@users.noreply.github.com>
|
|
6
6
|
License: MIT
|
|
@@ -12,9 +12,9 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Topic :: Home Automation
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.12.0
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
Provides-Extra: requirements
|
|
20
20
|
Provides-Extra: requirements_test
|