pypetkitapi 1.12.4__py3-none-any.whl → 1.12.6__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.
pypetkitapi/__init__.py CHANGED
@@ -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.4"
54
+ __version__ = "1.12.6"
55
55
 
56
56
  __all__ = [
57
57
  "CTW3",
pypetkitapi/bluetooth.py CHANGED
@@ -88,12 +88,13 @@ class BluetoothManager:
88
88
  """
89
89
  _LOGGER.debug("Opening BLE connection to fountain %s", fountain_id)
90
90
  water_fountain = await self._get_fountain_instance(fountain_id)
91
- if await self.check_relay_availability(fountain_id) is False:
92
- _LOGGER.debug("BLE relay not available (id: %s).", fountain_id)
93
- return False
94
91
  if water_fountain.is_connected is True:
95
92
  _LOGGER.debug("BLE connection already established (id %s)", fountain_id)
96
93
  return True
94
+ water_fountain.is_connected = False
95
+ if await self.check_relay_availability(fountain_id) is False:
96
+ _LOGGER.debug("BLE relay not available (id: %s).", fountain_id)
97
+ return False
97
98
  response = await self.client.req.request(
98
99
  method=HTTPMethod.POST,
99
100
  url=PetkitEndpoint.BLE_CONNECT,
@@ -106,7 +107,6 @@ class BluetoothManager:
106
107
  )
107
108
  if response != {"state": 1}:
108
109
  _LOGGER.debug("Unable to open a BLE connection (id %s)", fountain_id)
109
- water_fountain.is_connected = False
110
110
  return False
111
111
  for attempt in range(BLE_CONNECT_ATTEMPT):
112
112
  _LOGGER.debug(
@@ -125,7 +125,16 @@ class BluetoothManager:
125
125
  },
126
126
  headers=await self.client.get_session_id(),
127
127
  )
128
- if response == 1:
128
+ if response == 0:
129
+ # Wait for 4 seconds before polling again, connection is still in progress
130
+ await asyncio.sleep(4)
131
+ elif response == -1:
132
+ _LOGGER.debug("Failed to establish BLE connection (id %s)", fountain_id)
133
+ water_fountain.last_ble_poll = datetime.now().strftime(
134
+ "%Y-%m-%dT%H:%M:%S.%f"
135
+ )
136
+ return False
137
+ elif response == 1:
129
138
  _LOGGER.debug(
130
139
  "BLE connection established successfully (id %s)", fountain_id
131
140
  )
@@ -134,13 +143,11 @@ class BluetoothManager:
134
143
  "%Y-%m-%dT%H:%M:%S.%f"
135
144
  )
136
145
  return True
137
- await asyncio.sleep(4)
138
146
  _LOGGER.debug(
139
- "Failed to establish BLE connection after %s attempts (id %s)",
147
+ "Failed to establish BLE connection reached the max %s attempts allowed (id %s)",
140
148
  BLE_CONNECT_ATTEMPT,
141
149
  fountain_id,
142
150
  )
143
- water_fountain.is_connected = False
144
151
  return False
145
152
 
146
153
  async def close_ble_connection(self, fountain_id: int) -> None:
pypetkitapi/const.py CHANGED
@@ -12,7 +12,7 @@ DEVICE_STATS = "deviceStats"
12
12
  PET_DATA = "petData"
13
13
 
14
14
  # Bluetooth
15
- BLE_CONNECT_ATTEMPT = 4
15
+ BLE_CONNECT_ATTEMPT = 32
16
16
  BLE_START_TRAME = [250, 252, 253]
17
17
  BLE_END_TRAME = [251]
18
18
 
@@ -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,7 +44,7 @@ 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
49
  DEVICES_PURIFIER = [K2]
48
50
  # All devices
@@ -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.0.2"
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})"
pypetkitapi/media.py CHANGED
@@ -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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pypetkitapi
3
- Version: 1.12.4
3
+ Version: 1.12.6
4
4
  Summary: Python client for PetKit API
5
5
  License: MIT
6
6
  Author: Jezza34000
@@ -1,19 +1,19 @@
1
- pypetkitapi/__init__.py,sha256=6zdURz_Sh7_mlBC4sHerwEOSoagp00FRioQHhswxuBA,2107
2
- pypetkitapi/bluetooth.py,sha256=Nhmuy6s6V4_A5pgf_WrUc_3cW9P5gh6mSDN23vGoiBY,9534
1
+ pypetkitapi/__init__.py,sha256=9aYDp2exciCKqaGEwL9K23dY3sH05gih03womG0NnII,2107
2
+ pypetkitapi/bluetooth.py,sha256=1zEZIrKNTttrZpqBiQ-6V37Uphft5_T8CH9OBfYjwxE,9915
3
3
  pypetkitapi/client.py,sha256=62QzLypzCa6nEfR-Ihams6uQuYyKpu6yrFfnjfFu1Cc,30057
4
4
  pypetkitapi/command.py,sha256=k04iC0ONiFx7pkr-LJI7qT3RprQ3ojT0jP6KWQk8eTQ,7514
5
- pypetkitapi/const.py,sha256=76mR_g6qpqmkSj968W0lLyQAkAPenjk5dcs8ryWJUVA,4732
5
+ pypetkitapi/const.py,sha256=tDCbvDbJHKZEy6L5Api59O1NE3mi9X61YTYTBv_6E9E,4767
6
6
  pypetkitapi/containers.py,sha256=QshQ3PaN858jy0nSjeIZyyLijK_AfpzrIZeq2SDoqXQ,4816
7
7
  pypetkitapi/exceptions.py,sha256=4BXUyYXLfZjNxdnOGJPjyE9ASIl7JmQphjws87jvHtE,1631
8
8
  pypetkitapi/feeder_container.py,sha256=PhidWd5WpsZqtdKZy60PzE67YXgQfApjm8CqvMCHK3U,14743
9
9
  pypetkitapi/litter_container.py,sha256=VIQZyZwmsxgMsV80Bc1lnYMqJyTZSaiqwE4Y_CNTD9Q,19338
10
- pypetkitapi/media.py,sha256=3PrjKNXYX7F1wXyXPxWFAJsQk2jlaFL7-dwVpMwy94o,26889
10
+ pypetkitapi/media.py,sha256=LNY3khU5eZN4i1MGHxJaPHcf3LA1fFaPVkn-wdn0YLI,27168
11
11
  pypetkitapi/purifier_container.py,sha256=ssyIxhNben5XJ4KlQTXTrtULg2ji6DqHqjzOq08d1-I,2491
12
12
  pypetkitapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  pypetkitapi/schedule_container.py,sha256=ycIHeQHkVILDp7ZBjaVdGI_9rhHrgqeKBfvQAX3JMGE,2071
14
14
  pypetkitapi/utils.py,sha256=z7325kcJQUburnF28HSXrJMvY_gY9007K73Zwxp-4DQ,743
15
15
  pypetkitapi/water_fountain_container.py,sha256=5J0b-fDZYcFLNX2El7fifv8H6JMhBCt-ttxSow1ozRQ,6787
16
- pypetkitapi-1.12.4.dist-info/LICENSE,sha256=u5jNkZEn6YMrtN4Kr5rU3TcBJ5-eAt0qMx4JDsbsnzM,1074
17
- pypetkitapi-1.12.4.dist-info/METADATA,sha256=4UPiRUzvSuL7N9BsK_NwH-s5FjzL-SA6ZK1n3z7cFBE,6946
18
- pypetkitapi-1.12.4.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
19
- pypetkitapi-1.12.4.dist-info/RECORD,,
16
+ pypetkitapi-1.12.6.dist-info/LICENSE,sha256=u5jNkZEn6YMrtN4Kr5rU3TcBJ5-eAt0qMx4JDsbsnzM,1074
17
+ pypetkitapi-1.12.6.dist-info/METADATA,sha256=QaAgcHSi7rs1mRuz_LKb7zFPD3QHlqhnwd680OBC0bs,6946
18
+ pypetkitapi-1.12.6.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
19
+ pypetkitapi-1.12.6.dist-info/RECORD,,