pypetkitapi 1.12.5__tar.gz → 1.13.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pypetkitapi
3
- Version: 1.12.5
3
+ Version: 1.13.0
4
4
  Summary: Python client for PetKit API
5
5
  License: MIT
6
6
  Author: Jezza34000
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
23
23
 
24
24
  ---
25
25
 
26
- [![Lifecycle:Maturing](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://github.com/Jezza34000/py-petkit-api/)
26
+ [![Lifecycle:Maturing](https://img.shields.io/badge/Lifecycle-Stable-007EC6)](https://github.com/Jezza34000/py-petkit-api/)
27
27
  [![Python Version](https://img.shields.io/pypi/pyversions/pypetkitapi)][python version] [![Actions status](https://github.com/Jezza34000/py-petkit-api/workflows/CI/badge.svg)](https://github.com/Jezza34000/py-petkit-api/actions)
28
28
 
29
29
  [![PyPI](https://img.shields.io/pypi/v/pypetkitapi.svg)][pypi_] [![PyPI Downloads](https://static.pepy.tech/badge/pypetkitapi)](https://pepy.tech/projects/pypetkitapi)
@@ -2,7 +2,7 @@
2
2
 
3
3
  ---
4
4
 
5
- [![Lifecycle:Maturing](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://github.com/Jezza34000/py-petkit-api/)
5
+ [![Lifecycle:Maturing](https://img.shields.io/badge/Lifecycle-Stable-007EC6)](https://github.com/Jezza34000/py-petkit-api/)
6
6
  [![Python Version](https://img.shields.io/pypi/pyversions/pypetkitapi)][python version] [![Actions status](https://github.com/Jezza34000/py-petkit-api/workflows/CI/badge.svg)](https://github.com/Jezza34000/py-petkit-api/actions)
7
7
 
8
8
  [![PyPI](https://img.shields.io/pypi/v/pypetkitapi.svg)][pypi_] [![PyPI Downloads](https://static.pepy.tech/badge/pypetkitapi)](https://pepy.tech/projects/pypetkitapi)
@@ -51,7 +51,7 @@ from .media import DownloadDecryptMedia, MediaCloud, MediaFile, MediaManager
51
51
  from .purifier_container import Purifier
52
52
  from .water_fountain_container import WaterFountain
53
53
 
54
- __version__ = "1.12.5"
54
+ __version__ = "1.13.0"
55
55
 
56
56
  __all__ = [
57
57
  "CTW3",
@@ -98,7 +98,7 @@ class DeviceAction(StrEnum):
98
98
  END = "end_action"
99
99
  START = "start_action"
100
100
  STOP = "stop_action"
101
- # Purifier only
101
+ # Purifier K2 only
102
102
  MODE = "mode_action"
103
103
  # All devices
104
104
  POWER = "power_action"
@@ -159,8 +159,8 @@ def get_endpoint_reset_desiccant(device):
159
159
 
160
160
  def get_endpoint_update_setting(device):
161
161
  """Get the endpoint for the device"""
162
- if device.device_nfo.device_type == FEEDER_MINI:
163
- return PetkitEndpoint.UPDATE_SETTING_FEEDER_MINI
162
+ if device.device_nfo.device_type in [FEEDER_MINI, K3]:
163
+ return PetkitEndpoint.UPDATE_SETTING_OLD
164
164
  return PetkitEndpoint.UPDATE_SETTING
165
165
 
166
166
 
@@ -28,7 +28,9 @@ T3 = "t3"
28
28
  T4 = "t4"
29
29
  T5 = "t5"
30
30
  T6 = "t6"
31
+ W4 = "w4"
31
32
  W5 = "w5"
33
+ CTW2 = "ctw2"
32
34
  CTW3 = "ctw3"
33
35
  K2 = "k2"
34
36
  K3 = "k3"
@@ -42,9 +44,9 @@ LITTER_NO_CAMERA = [T3, T4]
42
44
  FEEDER_WITH_CAMERA = [D4H, D4SH]
43
45
  DEVICES_FEEDER = [FEEDER, FEEDER_MINI, D3, D4, D4S, D4H, D4SH]
44
46
  # Water Fountain
45
- DEVICES_WATER_FOUNTAIN = [W5, CTW3]
47
+ DEVICES_WATER_FOUNTAIN = [W4, W5, CTW2, CTW3]
46
48
  # Purifier
47
- DEVICES_PURIFIER = [K2]
49
+ DEVICES_PURIFIER = [K2, K3]
48
50
  # All devices
49
51
  ALL_DEVICES = [
50
52
  *DEVICES_LITTER_BOX,
@@ -76,7 +78,7 @@ class Header(StrEnum):
76
78
  ACCEPT = "*/*"
77
79
  ACCEPT_LANG = "en-US;q=1, it-US;q=0.9"
78
80
  ENCODING = "gzip, deflate"
79
- API_VERSION = "11.4.0"
81
+ API_VERSION = "12.1.0"
80
82
  CONTENT_TYPE = "application/x-www-form-urlencoded"
81
83
  AGENT = "okhttp/3.12.11"
82
84
  CLIENT = f"{Client.PLATFORM_TYPE}({Client.OS_VERSION};{Client.MODEL_NAME})"
@@ -150,7 +152,7 @@ class PetkitEndpoint(StrEnum):
150
152
  GET_DEVICE_RECORD = "getDeviceRecord"
151
153
  GET_DEVICE_RECORD_RELEASE = "getDeviceRecordRelease"
152
154
  UPDATE_SETTING = "updateSettings"
153
- UPDATE_SETTING_FEEDER_MINI = "update"
155
+ UPDATE_SETTING_OLD = "update"
154
156
 
155
157
  # Bluetooth
156
158
  BLE_AS_RELAY = "ble/ownSupportBleDevices"
@@ -21,6 +21,7 @@ from pypetkitapi.containers import (
21
21
  UserDevice,
22
22
  Wifi,
23
23
  )
24
+ from pypetkitapi.purifier_container import Purifier
24
25
 
25
26
 
26
27
  class SettingsLitter(BaseModel):
@@ -386,31 +387,6 @@ class PetOutGraph(BaseModel):
386
387
  }
387
388
 
388
389
 
389
- class K3Device(BaseModel):
390
- """Dataclass for K3 device data."""
391
-
392
- battery: int | None = None
393
- created_at: datetime | None = Field(None, alias="createdAt")
394
- firmware: int | None = None
395
- hardware: int | None = None
396
- id: int | None = None
397
- lighting: int | None = None
398
- liquid: int | None = None
399
- liquid_lack: int | None = Field(None, alias="liquidLack")
400
- mac: str | None = None
401
- name: str | None = None
402
- refreshing: int | None = None
403
- relate_t4: int | None = Field(None, alias="relateT4")
404
- relation: dict | None = None
405
- secret: str | None = None
406
- settings: dict | None = None
407
- sn: str | None = None
408
- timezone: float | None = None
409
- update_at: datetime | None = Field(None, alias="updateAt")
410
- user_id: str | None = Field(None, alias="userId")
411
- voltage: int | None = None
412
-
413
-
414
390
  class Litter(BaseModel):
415
391
  """Dataclass for Litter Data.
416
392
  Supported devices = T3, T4, T5, T6
@@ -425,7 +401,7 @@ class Litter(BaseModel):
425
401
  firmware_details: list[FirmwareDetail] = Field(alias="firmwareDetails")
426
402
  hardware: int
427
403
  id: int
428
- k3_device: K3Device | None = Field(None, alias="k3Device")
404
+ k3_device: Purifier | None = Field(None, alias="k3Device")
429
405
  is_pet_out_tips: int | None = Field(None, alias="isPetOutTips")
430
406
  locale: str | None = None
431
407
  mac: str | None = None
@@ -24,6 +24,7 @@ from pypetkitapi.const import (
24
24
  FEEDER_WITH_CAMERA,
25
25
  LITTER_WITH_CAMERA,
26
26
  MediaType,
27
+ PetkitEndpoint,
27
28
  RecordTypeLST,
28
29
  )
29
30
  from pypetkitapi.litter_container import LitterRecord
@@ -353,7 +354,7 @@ class MediaManager:
353
354
  user_id=user_id,
354
355
  image=item.preview,
355
356
  video=await self.construct_video_url(
356
- device_type, item.media_api, user_id, cp_sub
357
+ device_type, item, user_id, cp_sub
357
358
  ),
358
359
  filepath=filepath,
359
360
  aes_key=item.aes_key,
@@ -407,7 +408,7 @@ class MediaManager:
407
408
  user_id=user_id,
408
409
  image=record.preview,
409
410
  video=await self.construct_video_url(
410
- device_type, record.media_api, user_id, cp_sub
411
+ device_type, record, user_id, cp_sub
411
412
  ),
412
413
  filepath=filepath,
413
414
  aes_key=record.aes_key,
@@ -442,22 +443,26 @@ class MediaManager:
442
443
  @staticmethod
443
444
  async def construct_video_url(
444
445
  device_type: str | None,
445
- media_url: str | None,
446
+ event_data: LitterRecord | RecordsItems,
446
447
  user_id: int,
447
448
  cp_sub: bool | None,
448
449
  ) -> str | None:
449
450
  """Construct the video URL.
450
451
  :param device_type: Device type
451
- :param media_url: Media URL
452
+ :param event_data: LitterRecord | RecordsItems
452
453
  :param user_id: User ID
453
454
  :param cp_sub: Cpsub value
454
455
  :return: Constructed video URL
455
456
  """
456
- if not media_url or not user_id or not cp_sub:
457
+ if not hasattr(event_data, "media_api") or not user_id or not cp_sub:
457
458
  return None
458
- params = parse_qs(urlparse(media_url).query)
459
+ params = parse_qs(str(urlparse(event_data.media_api).query))
459
460
  param_dict = {k: v[0] for k, v in params.items()}
460
- return f"/{device_type}/cloud/video?startTime={param_dict.get("startTime")}&deviceId={param_dict.get("deviceId")}&userId={user_id}&mark={param_dict.get("mark")}"
461
+ url = f"/{device_type}/{PetkitEndpoint.CLOUD_VIDEO}?startTime={param_dict.get('startTime')}&deviceId={param_dict.get('deviceId')}&userId={user_id}&mark={param_dict.get('mark')}"
462
+ if hasattr(event_data, "eat_end_time"):
463
+ # Special case for Eat video (need to add endTime)
464
+ url += f"&endTime={event_data.eat_end_time}"
465
+ return url
461
466
 
462
467
  @staticmethod
463
468
  async def _get_timestamp(item) -> int | None:
@@ -4,7 +4,7 @@ from typing import Any, ClassVar
4
4
 
5
5
  from pydantic import BaseModel, Field
6
6
 
7
- from pypetkitapi.const import DEVICE_DATA, PetkitEndpoint
7
+ from pypetkitapi.const import DEVICE_DATA, K3, PetkitEndpoint
8
8
  from pypetkitapi.containers import Device, FirmwareDetail, Wifi
9
9
 
10
10
 
@@ -12,9 +12,11 @@ class Settings(BaseModel):
12
12
  """Dataclass for settings data."""
13
13
 
14
14
  auto_work: int | None = Field(None, alias="autoWork")
15
+ fixed_time_refresh: int | None = Field(None, alias="fixedTimeRefresh")
15
16
  lack_notify: int | None = Field(None, alias="lackNotify")
16
17
  light_mode: int | None = Field(None, alias="lightMode")
17
18
  light_range: list[int] | None = Field(None, alias="lightRange")
19
+ liquid_lack_switch: int | None = Field(None, alias="liquidLackSwitch")
18
20
  log_notify: int | None = Field(None, alias="logNotify")
19
21
  manual_lock: int | None = Field(None, alias="manualLock")
20
22
  sound: int | None = None
@@ -42,29 +44,41 @@ class Purifier(BaseModel):
42
44
 
43
45
  data_type: ClassVar[str] = DEVICE_DATA
44
46
 
47
+ battery: int | None = None
45
48
  bt_mac: str | None = Field(None, alias="btMac")
46
49
  created_at: str | None = Field(None, alias="createdAt")
47
- firmware: str | None = None
50
+ firmware: str | int | None = None
48
51
  firmware_details: list[FirmwareDetail] | None = Field(None, alias="firmwareDetails")
49
52
  hardware: int | None = None
50
53
  id: int | None = None
54
+ lighting: int | None = None
55
+ liquid: int | None = None
56
+ liquid_lack: int | None = Field(None, alias="liquidLack")
51
57
  locale: str | None = None
52
58
  mac: str | None = None
53
59
  name: str | None = None
60
+ refreshing: int | None = None
61
+ relate_t4: int | None = Field(None, alias="relateT4")
54
62
  relation: dict[str, str]
55
63
  secret: str | None = None
56
64
  settings: Settings | None = None
57
65
  share_open: int | None = Field(None, alias="shareOpen")
58
66
  signup_at: str | None = Field(None, alias="signupAt")
59
67
  sn: str | None = None
68
+ spray_times: int | None = Field(None, alias="sprayTimes")
60
69
  state: State | None = None
61
70
  timezone: float | None = None
71
+ update_at: str | None = Field(None, alias="updateAt")
72
+ user_id: str | None = Field(None, alias="userId")
73
+ voltage: int | None = None
62
74
  work_time: list[tuple[int, int]] | None = Field(None, alias="workTime")
63
75
  device_nfo: Device | None = None
64
76
 
65
77
  @classmethod
66
78
  def get_endpoint(cls, device_type: str) -> str:
67
79
  """Get the endpoint URL for the given device type."""
80
+ if device_type == K3:
81
+ return PetkitEndpoint.DEVICE_DATA
68
82
  return PetkitEndpoint.DEVICE_DETAIL
69
83
 
70
84
  @classmethod
@@ -85,7 +85,6 @@ select = [
85
85
  "S317", # suspicious-xml-sax-usage
86
86
  "S318", # suspicious-xml-mini-dom-usage
87
87
  "S319", # suspicious-xml-pull-dom-usage
88
- "S320", # suspicious-xmle-tree-usage
89
88
  "S601", # paramiko-call
90
89
  "S602", # subprocess-popen-with-shell-equals-true
91
90
  "S604", # call-with-shell-equals-true
@@ -187,7 +186,7 @@ build-backend = "poetry.core.masonry.api"
187
186
 
188
187
  [tool.poetry]
189
188
  name = "pypetkitapi"
190
- version = "1.12.5"
189
+ version = "1.13.0"
191
190
  description = "Python client for PetKit API"
192
191
  authors = ["Jezza34000 <info@mail.com>"]
193
192
  readme = "README.md"
@@ -209,7 +208,7 @@ ruff = "^0.8.1"
209
208
  types-aiofiles = "^24.1.0.20240626"
210
209
 
211
210
  [tool.bumpver]
212
- current_version = "1.12.5"
211
+ current_version = "1.13.0"
213
212
  version_pattern = "MAJOR.MINOR.PATCH"
214
213
  commit_message = "bump version {old_version} -> {new_version}"
215
214
  tag_message = "{new_version}"
File without changes