pyezvizapi 1.0.2.2__py3-none-any.whl → 1.0.2.3__py3-none-any.whl
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.
- pyezvizapi/camera.py +10 -139
- pyezvizapi/utils.py +156 -0
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/METADATA +1 -1
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/RECORD +9 -9
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/WHEEL +0 -0
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/entry_points.txt +0 -0
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/licenses/LICENSE +0 -0
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/licenses/LICENSE.md +0 -0
- {pyezvizapi-1.0.2.2.dist-info → pyezvizapi-1.0.2.3.dist-info}/top_level.txt +0 -0
pyezvizapi/camera.py
CHANGED
|
@@ -4,14 +4,17 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import datetime
|
|
6
6
|
import logging
|
|
7
|
-
import re
|
|
8
7
|
from typing import TYPE_CHECKING, Any, Literal, TypedDict, cast
|
|
9
|
-
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
10
8
|
|
|
11
9
|
from .constants import BatteryCameraWorkMode, DeviceSwitchType, SoundMode
|
|
12
10
|
from .exceptions import PyEzvizError
|
|
13
11
|
from .models import EzvizDeviceRecord
|
|
14
|
-
from .utils import
|
|
12
|
+
from .utils import (
|
|
13
|
+
compute_motion_from_alarm,
|
|
14
|
+
fetch_nested_value,
|
|
15
|
+
parse_timezone_value,
|
|
16
|
+
string_to_list,
|
|
17
|
+
)
|
|
15
18
|
|
|
16
19
|
if TYPE_CHECKING:
|
|
17
20
|
from .client import EzvizClient
|
|
@@ -172,110 +175,10 @@ class EzvizCamera:
|
|
|
172
175
|
|
|
173
176
|
Prefer numeric epoch fields if available to avoid parsing localized strings.
|
|
174
177
|
"""
|
|
175
|
-
# Use timezone-aware datetimes. Compute both camera-local and UTC "now".
|
|
176
178
|
tzinfo = self._get_tzinfo()
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
# Prefer epoch fields if available
|
|
181
|
-
epoch = self._last_alarm.get("alarmStartTime") or self._last_alarm.get(
|
|
182
|
-
"alarmTime"
|
|
183
|
-
)
|
|
184
|
-
last_alarm_dt: datetime.datetime | None = None
|
|
185
|
-
# Capture string time if present so we can cross-check epoch skew
|
|
186
|
-
raw_time_str = str(
|
|
187
|
-
self._last_alarm.get("alarmStartTimeStr")
|
|
188
|
-
or self._last_alarm.get("alarmTimeStr")
|
|
189
|
-
or ""
|
|
179
|
+
active, seconds_out, last_alarm_str = compute_motion_from_alarm(
|
|
180
|
+
self._last_alarm, tzinfo
|
|
190
181
|
)
|
|
191
|
-
if epoch is not None:
|
|
192
|
-
try:
|
|
193
|
-
# Accept int/float/str; auto-detect ms vs s
|
|
194
|
-
if isinstance(epoch, str):
|
|
195
|
-
epoch = float(epoch)
|
|
196
|
-
ts = float(epoch)
|
|
197
|
-
if ts > 1e11: # very likely milliseconds
|
|
198
|
-
ts = ts / 1000.0
|
|
199
|
-
# Convert epoch to UTC for robust delta; derive display time in camera tz
|
|
200
|
-
event_utc = datetime.datetime.fromtimestamp(ts, tz=datetime.UTC)
|
|
201
|
-
last_alarm_dt = event_utc.astimezone(tzinfo)
|
|
202
|
-
# Some devices appear to report epoch as local time rather than UTC.
|
|
203
|
-
# If the provided string timestamp exists and differs significantly
|
|
204
|
-
# from the epoch-based time, reinterpret the epoch as local time.
|
|
205
|
-
if raw_time_str:
|
|
206
|
-
raw_norm = raw_time_str
|
|
207
|
-
if "Today" in raw_norm:
|
|
208
|
-
raw_norm = raw_norm.replace("Today", str(now_local.date()))
|
|
209
|
-
try:
|
|
210
|
-
dt_str_local = datetime.datetime.strptime(
|
|
211
|
-
raw_norm, "%Y-%m-%d %H:%M:%S"
|
|
212
|
-
).replace(tzinfo=tzinfo)
|
|
213
|
-
diff = abs(
|
|
214
|
-
(
|
|
215
|
-
event_utc
|
|
216
|
-
- dt_str_local.astimezone(datetime.UTC)
|
|
217
|
-
).total_seconds()
|
|
218
|
-
)
|
|
219
|
-
if diff > 120:
|
|
220
|
-
# Reinterpret the epoch as local clock time in camera tz
|
|
221
|
-
naive_utc = datetime.datetime.fromtimestamp(ts, tz=datetime.UTC).replace(tzinfo=None)
|
|
222
|
-
event_local_reint = naive_utc.replace(tzinfo=tzinfo)
|
|
223
|
-
event_utc = event_local_reint.astimezone(datetime.UTC)
|
|
224
|
-
last_alarm_dt = event_local_reint
|
|
225
|
-
except ValueError:
|
|
226
|
-
pass
|
|
227
|
-
except (
|
|
228
|
-
TypeError,
|
|
229
|
-
ValueError,
|
|
230
|
-
OSError,
|
|
231
|
-
): # fall back to string parsing below
|
|
232
|
-
last_alarm_dt = None
|
|
233
|
-
|
|
234
|
-
last_alarm_str: str | None = None
|
|
235
|
-
if last_alarm_dt is None:
|
|
236
|
-
# Fall back to string parsing
|
|
237
|
-
raw = raw_time_str
|
|
238
|
-
if not raw:
|
|
239
|
-
return
|
|
240
|
-
if "Today" in raw:
|
|
241
|
-
raw = raw.replace("Today", str(now_local.date()))
|
|
242
|
-
try:
|
|
243
|
-
last_alarm_dt = datetime.datetime.strptime(
|
|
244
|
-
raw, "%Y-%m-%d %H:%M:%S"
|
|
245
|
-
).replace(tzinfo=tzinfo)
|
|
246
|
-
last_alarm_str = last_alarm_dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
247
|
-
except ValueError: # Unrecognized format; give up gracefully
|
|
248
|
-
_LOGGER.debug(
|
|
249
|
-
"Unrecognized alarm time format for %s: %s", self._serial, raw
|
|
250
|
-
)
|
|
251
|
-
self._alarmmotiontrigger = {
|
|
252
|
-
"alarm_trigger_active": False,
|
|
253
|
-
"timepassed": None,
|
|
254
|
-
"last_alarm_time_str": raw or None,
|
|
255
|
-
}
|
|
256
|
-
return
|
|
257
|
-
else:
|
|
258
|
-
# We selected epoch path; format a human-readable local string
|
|
259
|
-
last_alarm_str = last_alarm_dt.astimezone(tzinfo).strftime(
|
|
260
|
-
"%Y-%m-%d %H:%M:%S"
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
# Compute elapsed seconds since the last alarm. If the timestamp is
|
|
264
|
-
# somehow in the future (timezone mismatch or clock skew), do not
|
|
265
|
-
# report a motion trigger; clamp the exposed seconds to 0.0.
|
|
266
|
-
# Use UTC delta when epoch was provided; otherwise compute in camera tz.
|
|
267
|
-
if epoch is not None and last_alarm_dt is not None:
|
|
268
|
-
event_utc_for_delta = last_alarm_dt.astimezone(datetime.UTC)
|
|
269
|
-
delta = now_utc - event_utc_for_delta
|
|
270
|
-
else:
|
|
271
|
-
delta = now_local - last_alarm_dt
|
|
272
|
-
seconds = float(delta.total_seconds())
|
|
273
|
-
if seconds < 0:
|
|
274
|
-
active = False
|
|
275
|
-
seconds_out = 0.0
|
|
276
|
-
else:
|
|
277
|
-
active = seconds < 60.0
|
|
278
|
-
seconds_out = seconds
|
|
279
182
|
|
|
280
183
|
self._alarmmotiontrigger = {
|
|
281
184
|
"alarm_trigger_active": active,
|
|
@@ -284,41 +187,9 @@ class EzvizCamera:
|
|
|
284
187
|
}
|
|
285
188
|
|
|
286
189
|
def _get_tzinfo(self) -> datetime.tzinfo:
|
|
287
|
-
"""Return tzinfo from camera setting if recognizable, else local tzinfo.
|
|
288
|
-
|
|
289
|
-
Attempts to parse common formats like 'UTC+02:00', 'GMT+8', '+0530', or IANA names.
|
|
290
|
-
Falls back to local timezone.
|
|
291
|
-
"""
|
|
190
|
+
"""Return tzinfo from camera setting if recognizable, else local tzinfo."""
|
|
292
191
|
tz_val = self.fetch_key(["STATUS", "optionals", "timeZone"])
|
|
293
|
-
|
|
294
|
-
if isinstance(tz_val, str) and "/" in tz_val:
|
|
295
|
-
try:
|
|
296
|
-
return ZoneInfo(tz_val)
|
|
297
|
-
except ZoneInfoNotFoundError:
|
|
298
|
-
pass
|
|
299
|
-
# Offset formats
|
|
300
|
-
offset_minutes: int | None = None
|
|
301
|
-
if isinstance(tz_val, int):
|
|
302
|
-
# Heuristic: treat small absolute values as hours, large as minutes/seconds
|
|
303
|
-
if -14 <= tz_val <= 14:
|
|
304
|
-
offset_minutes = tz_val * 60
|
|
305
|
-
elif -24 * 60 <= tz_val <= 24 * 60:
|
|
306
|
-
offset_minutes = tz_val
|
|
307
|
-
elif -24 * 3600 <= tz_val <= 24 * 3600:
|
|
308
|
-
offset_minutes = int(tz_val / 60)
|
|
309
|
-
elif isinstance(tz_val, str):
|
|
310
|
-
s = tz_val.strip().upper().replace("UTC", "").replace("GMT", "")
|
|
311
|
-
# Normalize formats like '+02:00', '+0200', '+2'
|
|
312
|
-
m = re.match(r"^([+-]?)(\d{1,2})(?::?(\d{2}))?$", s)
|
|
313
|
-
if m:
|
|
314
|
-
sign = -1 if m.group(1) == "-" else 1
|
|
315
|
-
hours = int(m.group(2))
|
|
316
|
-
minutes = int(m.group(3)) if m.group(3) else 0
|
|
317
|
-
offset_minutes = sign * (hours * 60 + minutes)
|
|
318
|
-
if offset_minutes is not None:
|
|
319
|
-
return datetime.timezone(datetime.timedelta(minutes=offset_minutes))
|
|
320
|
-
# Fallback to local timezone
|
|
321
|
-
return datetime.datetime.now().astimezone().tzinfo or datetime.UTC
|
|
192
|
+
return parse_timezone_value(tz_val)
|
|
322
193
|
|
|
323
194
|
def _is_alarm_schedules_enabled(self) -> bool:
|
|
324
195
|
"""Check if alarm schedules enabled."""
|
pyezvizapi/utils.py
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import datetime
|
|
5
6
|
from hashlib import md5
|
|
6
7
|
import json
|
|
7
8
|
import logging
|
|
9
|
+
import re as _re
|
|
8
10
|
from typing import Any
|
|
9
11
|
import uuid
|
|
12
|
+
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
10
13
|
|
|
11
14
|
from Crypto.Cipher import AES
|
|
12
15
|
|
|
@@ -188,3 +191,156 @@ def generate_unique_code() -> str:
|
|
|
188
191
|
mac_int = uuid.getnode()
|
|
189
192
|
mac_str = ":".join(f"{(mac_int >> i) & 0xFF:02x}" for i in range(40, -1, -8))
|
|
190
193
|
return md5(mac_str.encode("utf-8")).hexdigest()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
# Time helpers for alarm/motion handling
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
def normalize_alarm_time(
|
|
201
|
+
last_alarm: dict[str, Any], tzinfo: datetime.tzinfo
|
|
202
|
+
) -> tuple[datetime.datetime | None, datetime.datetime | None, str | None]:
|
|
203
|
+
"""Normalize EZVIZ alarm timestamps.
|
|
204
|
+
|
|
205
|
+
Returns a tuple of:
|
|
206
|
+
- alarm_dt_local: datetime in the camera's timezone (for display)
|
|
207
|
+
- alarm_dt_utc: datetime in UTC (for robust delta calculation)
|
|
208
|
+
- alarm_time_str: formatted 'YYYY-MM-DD HH:MM:SS' string in camera tz
|
|
209
|
+
|
|
210
|
+
Behavior:
|
|
211
|
+
- Prefer epoch fields (alarmStartTime/alarmTime). Interpret as UTC by default.
|
|
212
|
+
- If a string time exists and differs from the epoch by >120 seconds,
|
|
213
|
+
reinterpret the epoch as if reported in camera local time.
|
|
214
|
+
- If no epoch, fall back to parsing the string time in the camera tz.
|
|
215
|
+
"""
|
|
216
|
+
# Prefer epoch
|
|
217
|
+
epoch = last_alarm.get("alarmStartTime") or last_alarm.get("alarmTime")
|
|
218
|
+
raw_time_str = str(
|
|
219
|
+
last_alarm.get("alarmStartTimeStr") or last_alarm.get("alarmTimeStr") or ""
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
alarm_dt_local: datetime.datetime | None = None
|
|
223
|
+
alarm_dt_utc: datetime.datetime | None = None
|
|
224
|
+
alarm_str: str | None = None
|
|
225
|
+
|
|
226
|
+
now_local = datetime.datetime.now(tz=tzinfo)
|
|
227
|
+
|
|
228
|
+
if epoch is not None:
|
|
229
|
+
try:
|
|
230
|
+
ts = float(epoch if not isinstance(epoch, str) else float(epoch))
|
|
231
|
+
if ts > 1e11: # milliseconds
|
|
232
|
+
ts /= 1000.0
|
|
233
|
+
event_utc = datetime.datetime.fromtimestamp(ts, tz=datetime.UTC)
|
|
234
|
+
alarm_dt_local = event_utc.astimezone(tzinfo)
|
|
235
|
+
alarm_dt_utc = event_utc
|
|
236
|
+
|
|
237
|
+
if raw_time_str:
|
|
238
|
+
raw_norm = raw_time_str.replace("Today", str(now_local.date()))
|
|
239
|
+
try:
|
|
240
|
+
dt_str_local = datetime.datetime.strptime(
|
|
241
|
+
raw_norm, "%Y-%m-%d %H:%M:%S"
|
|
242
|
+
).replace(tzinfo=tzinfo)
|
|
243
|
+
diff = abs(
|
|
244
|
+
(event_utc - dt_str_local.astimezone(datetime.UTC)).total_seconds()
|
|
245
|
+
)
|
|
246
|
+
if diff > 120:
|
|
247
|
+
# Reinterpret epoch as local clock time in camera tz
|
|
248
|
+
naive_utc = (
|
|
249
|
+
datetime.datetime.fromtimestamp(ts, tz=datetime.UTC)
|
|
250
|
+
.replace(tzinfo=None)
|
|
251
|
+
)
|
|
252
|
+
event_local_reint = naive_utc.replace(tzinfo=tzinfo)
|
|
253
|
+
alarm_dt_local = event_local_reint
|
|
254
|
+
alarm_dt_utc = event_local_reint.astimezone(datetime.UTC)
|
|
255
|
+
except ValueError:
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
if alarm_dt_local is not None:
|
|
259
|
+
alarm_str = alarm_dt_local.strftime("%Y-%m-%d %H:%M:%S")
|
|
260
|
+
return alarm_dt_local, alarm_dt_utc, alarm_str
|
|
261
|
+
# If conversion failed unexpectedly, fall through to string parsing
|
|
262
|
+
except (TypeError, ValueError, OSError):
|
|
263
|
+
alarm_dt_local = None
|
|
264
|
+
|
|
265
|
+
# Fallback to string parsing
|
|
266
|
+
if raw_time_str:
|
|
267
|
+
raw = raw_time_str.replace("Today", str(now_local.date()))
|
|
268
|
+
try:
|
|
269
|
+
alarm_dt_local = datetime.datetime.strptime(raw, "%Y-%m-%d %H:%M:%S").replace(
|
|
270
|
+
tzinfo=tzinfo
|
|
271
|
+
)
|
|
272
|
+
alarm_dt_utc = alarm_dt_local.astimezone(datetime.UTC)
|
|
273
|
+
alarm_str = alarm_dt_local.strftime("%Y-%m-%d %H:%M:%S")
|
|
274
|
+
except ValueError:
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
return alarm_dt_local, alarm_dt_utc, alarm_str
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def compute_motion_from_alarm(
|
|
281
|
+
last_alarm: dict[str, Any], tzinfo: datetime.tzinfo, window_seconds: float = 60.0
|
|
282
|
+
) -> tuple[bool, float, str | None]:
|
|
283
|
+
"""Compute motion state and seconds-since from an alarm payload.
|
|
284
|
+
|
|
285
|
+
Returns (active, seconds_since, last_alarm_time_str).
|
|
286
|
+
- Uses UTC for delta when epoch-derived UTC is available.
|
|
287
|
+
- Falls back to camera local tz deltas when only string times are present.
|
|
288
|
+
- Clamps negative deltas to 0.0 and deactivates motion.
|
|
289
|
+
"""
|
|
290
|
+
alarm_dt_local, alarm_dt_utc, alarm_str = normalize_alarm_time(last_alarm, tzinfo)
|
|
291
|
+
if alarm_dt_local is None:
|
|
292
|
+
return False, 0.0, None
|
|
293
|
+
|
|
294
|
+
now_local = datetime.datetime.now(tz=tzinfo).replace(microsecond=0)
|
|
295
|
+
now_utc = datetime.datetime.now(tz=datetime.UTC).replace(microsecond=0)
|
|
296
|
+
|
|
297
|
+
if alarm_dt_utc is not None:
|
|
298
|
+
delta = now_utc - alarm_dt_utc
|
|
299
|
+
else:
|
|
300
|
+
delta = now_local - alarm_dt_local
|
|
301
|
+
|
|
302
|
+
seconds = float(delta.total_seconds())
|
|
303
|
+
if seconds < 0:
|
|
304
|
+
return False, 0.0, alarm_str
|
|
305
|
+
|
|
306
|
+
return seconds < window_seconds, seconds, alarm_str
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def parse_timezone_value(tz_val: Any) -> datetime.tzinfo:
|
|
310
|
+
"""Parse EZVIZ timeZone value into a tzinfo.
|
|
311
|
+
|
|
312
|
+
Supports:
|
|
313
|
+
- IANA names like 'Europe/Paris'
|
|
314
|
+
- Offsets like 'UTC+02:00', 'GMT-5', '+0530', or integers (hours/minutes/seconds)
|
|
315
|
+
Falls back to the local system timezone, or UTC if unavailable.
|
|
316
|
+
"""
|
|
317
|
+
# IANA zone name
|
|
318
|
+
if isinstance(tz_val, str) and "/" in tz_val:
|
|
319
|
+
try:
|
|
320
|
+
return ZoneInfo(tz_val)
|
|
321
|
+
except ZoneInfoNotFoundError:
|
|
322
|
+
pass
|
|
323
|
+
|
|
324
|
+
# Numeric offsets
|
|
325
|
+
offset_minutes: int | None = None
|
|
326
|
+
if isinstance(tz_val, int):
|
|
327
|
+
if -14 <= tz_val <= 14:
|
|
328
|
+
offset_minutes = tz_val * 60
|
|
329
|
+
elif -24 * 60 <= tz_val <= 24 * 60:
|
|
330
|
+
offset_minutes = tz_val
|
|
331
|
+
elif -24 * 3600 <= tz_val <= 24 * 3600:
|
|
332
|
+
offset_minutes = int(tz_val / 60)
|
|
333
|
+
elif isinstance(tz_val, str):
|
|
334
|
+
s = tz_val.strip().upper().replace("UTC", "").replace("GMT", "")
|
|
335
|
+
m = _re.match(r"^([+-]?)(\d{1,2})(?::?(\d{2}))?$", s)
|
|
336
|
+
if m:
|
|
337
|
+
sign = -1 if m.group(1) == "-" else 1
|
|
338
|
+
hours = int(m.group(2))
|
|
339
|
+
minutes = int(m.group(3)) if m.group(3) else 0
|
|
340
|
+
offset_minutes = sign * (hours * 60 + minutes)
|
|
341
|
+
|
|
342
|
+
if offset_minutes is not None:
|
|
343
|
+
return datetime.timezone(datetime.timedelta(minutes=offset_minutes))
|
|
344
|
+
|
|
345
|
+
# Fallbacks
|
|
346
|
+
return datetime.datetime.now().astimezone().tzinfo or datetime.UTC
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
pyezvizapi/__init__.py,sha256=IDnIN_nfIISVwuy0cVBh4wspgAav6MuOJCQGajjyU3g,1881
|
|
2
2
|
pyezvizapi/__main__.py,sha256=SeV954H-AV-U1thNxRd7rWTGtSlfWyNzdrjF8gikYus,20777
|
|
3
3
|
pyezvizapi/api_endpoints.py,sha256=rk6VinLVCn-B6DxnhfV79liplNpgUsipNbTEa_MRVwU,2755
|
|
4
|
-
pyezvizapi/camera.py,sha256=
|
|
4
|
+
pyezvizapi/camera.py,sha256=Pl5oIEdrFcv1Hz5sQI1IyyJIDCMjOjQdtExgKzmLoK8,22102
|
|
5
5
|
pyezvizapi/cas.py,sha256=ISmb-eTPuacI10L87lULbQ-oDMBuygO7Tf-s9f-tvYE,5995
|
|
6
6
|
pyezvizapi/client.py,sha256=Bp5eQbn4-pjsZicfpWy6jD5bDjQeYFw-SN1p0uzKJRY,71782
|
|
7
7
|
pyezvizapi/constants.py,sha256=SqdJRQSRdVYQxMgJa__AgorzdWglgA4MM4H2fq3QLAE,12633
|
|
@@ -11,11 +11,11 @@ pyezvizapi/models.py,sha256=NQzwTP0yEe2IWU-Vc6nAn87xulpTuo0MX2Rcf0WxifA,4176
|
|
|
11
11
|
pyezvizapi/mqtt.py,sha256=aOL-gexZgYvCCaNQ03M4vZan91d5p2Fl_qsFykn9NW4,22365
|
|
12
12
|
pyezvizapi/test_cam_rtsp.py,sha256=WGSM5EiOTl_r1mWHoMb7bXHm_BCn1P9X_669YQ38r6k,4903
|
|
13
13
|
pyezvizapi/test_mqtt.py,sha256=Orn-fwZPJIE4G5KROMX0MRAkLwU6nLb9LUtXyb2ZCQs,4147
|
|
14
|
-
pyezvizapi/utils.py,sha256=
|
|
15
|
-
pyezvizapi-1.0.2.
|
|
16
|
-
pyezvizapi-1.0.2.
|
|
17
|
-
pyezvizapi-1.0.2.
|
|
18
|
-
pyezvizapi-1.0.2.
|
|
19
|
-
pyezvizapi-1.0.2.
|
|
20
|
-
pyezvizapi-1.0.2.
|
|
21
|
-
pyezvizapi-1.0.2.
|
|
14
|
+
pyezvizapi/utils.py,sha256=bOWLIytbELQfwBpA2LnhP1m8OthmOk9Vhh_uUXTFpoc,12124
|
|
15
|
+
pyezvizapi-1.0.2.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
16
|
+
pyezvizapi-1.0.2.3.dist-info/licenses/LICENSE.md,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
+
pyezvizapi-1.0.2.3.dist-info/METADATA,sha256=xvvts4etMltvpLLaIr0lcKhm1quwBYCJbFqltigk55U,695
|
|
18
|
+
pyezvizapi-1.0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
+
pyezvizapi-1.0.2.3.dist-info/entry_points.txt,sha256=_BSJ3eNb2H_AZkRdsv1s4mojqWn3N7m503ujvg1SudA,56
|
|
20
|
+
pyezvizapi-1.0.2.3.dist-info/top_level.txt,sha256=gMZTelIi8z7pXyTCQLLaIkxVRrDQ_lS2NEv0WgfHrHs,11
|
|
21
|
+
pyezvizapi-1.0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|