pypetkitapi 1.11.0__py3-none-any.whl → 1.11.2__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.11.0"
54
+ __version__ = "1.11.2"
55
55
 
56
56
  __all__ = [
57
57
  "CTW3",
pypetkitapi/media.py CHANGED
@@ -18,13 +18,14 @@ import aiohttp
18
18
  from Crypto.Cipher import AES
19
19
  from Crypto.Util.Padding import unpad
20
20
 
21
- from pypetkitapi import Feeder, Litter, PetKitClient, RecordType
21
+ from pypetkitapi import Feeder, Litter, PetKitClient, RecordsItems, RecordType
22
22
  from pypetkitapi.const import (
23
23
  FEEDER_WITH_CAMERA,
24
24
  LITTER_WITH_CAMERA,
25
25
  MediaType,
26
26
  RecordTypeLST,
27
27
  )
28
+ from pypetkitapi.litter_container import LitterRecord
28
29
 
29
30
  _LOGGER = logging.getLogger(__name__)
30
31
 
@@ -274,16 +275,19 @@ class MediaManager:
274
275
  )
275
276
 
276
277
  if not feeder_id:
277
- _LOGGER.error("Missing feeder_id for record")
278
+ _LOGGER.warning("Missing feeder_id for record")
278
279
  return media_files
279
280
 
280
281
  if not record.items:
281
282
  return media_files
282
283
 
283
284
  for item in record.items:
285
+ if not isinstance(item, RecordsItems):
286
+ _LOGGER.debug("Record is empty")
287
+ continue
284
288
  timestamp = await self._get_timestamp(item)
285
289
  if timestamp is None:
286
- _LOGGER.error("Missing timestamp for record item")
290
+ _LOGGER.warning("Missing timestamp for record item")
287
291
  continue
288
292
  if not item.event_id:
289
293
  # Skip feed event in the future
@@ -292,10 +296,10 @@ class MediaManager:
292
296
  )
293
297
  continue
294
298
  if not user_id:
295
- _LOGGER.error("Missing user_id for record item")
299
+ _LOGGER.warning("Missing user_id for record item")
296
300
  continue
297
301
  if not item.aes_key:
298
- _LOGGER.error("Missing aes_key for record item")
302
+ _LOGGER.warning("Missing aes_key for record item")
299
303
  continue
300
304
 
301
305
  date_str = await self.get_date_from_ts(timestamp)
@@ -330,21 +334,24 @@ class MediaManager:
330
334
  cp_sub = litter.cloud_product.subscribe if litter.cloud_product else None
331
335
 
332
336
  if not litter_id:
333
- _LOGGER.error("Missing litter_id for record")
337
+ _LOGGER.warning("Missing litter_id for record")
334
338
  return media_files
335
339
 
336
340
  if not device_type:
337
- _LOGGER.error("Missing device_type for record")
341
+ _LOGGER.warning("Missing device_type for record")
338
342
  return media_files
339
343
 
340
344
  if not user_id:
341
- _LOGGER.error("Missing user_id for record")
345
+ _LOGGER.warning("Missing user_id for record")
342
346
  return media_files
343
347
 
344
348
  if not records:
345
349
  return media_files
346
350
 
347
351
  for record in records:
352
+ if not isinstance(record, LitterRecord):
353
+ _LOGGER.debug("Record is empty")
354
+ continue
348
355
  if not record.event_id:
349
356
  _LOGGER.debug("Missing event_id for record item")
350
357
  continue
@@ -404,12 +411,12 @@ class MediaManager:
404
411
  return f"/{device_type}/cloud/video?startTime={param_dict.get("startTime")}&deviceId={param_dict.get("deviceId")}&userId={user_id}&mark={param_dict.get("mark")}"
405
412
 
406
413
  @staticmethod
407
- async def _get_timestamp(item) -> int:
414
+ async def _get_timestamp(item) -> int | None:
408
415
  """Extract timestamp from a record item and raise an exception if it is None.
409
416
  :param item: Record item
410
417
  :return: Timestamp
411
418
  """
412
- timestamp = (
419
+ return (
413
420
  item.timestamp
414
421
  or item.completed_at
415
422
  or item.eat_start_time
@@ -419,9 +426,6 @@ class MediaManager:
419
426
  or item.time
420
427
  or None
421
428
  )
422
- if timestamp is None:
423
- raise ValueError("Can't find timestamp in record item")
424
- return timestamp
425
429
 
426
430
 
427
431
  class DownloadDecryptMedia:
@@ -515,7 +519,7 @@ class DownloadDecryptMedia:
515
519
  ]
516
520
 
517
521
  if not segment_files:
518
- _LOGGER.error("No segment files found")
522
+ _LOGGER.warning("No segment files found")
519
523
  elif len(segment_files) == 1:
520
524
  _LOGGER.debug("Single file segment, no need to concatenate")
521
525
  elif len(segment_files) > 1:
@@ -535,7 +539,7 @@ class DownloadDecryptMedia:
535
539
 
536
540
  media_api = video_data.get("mediaApi", None)
537
541
  if not media_api:
538
- _LOGGER.error("Missing mediaApi in video data")
542
+ _LOGGER.warning("Missing mediaApi in video data")
539
543
  raise ValueError("Missing mediaApi in video data")
540
544
  return await self.client.extract_segments_m3u8(str(media_api))
541
545
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pypetkitapi
3
- Version: 1.11.0
3
+ Version: 1.11.2
4
4
  Summary: Python client for PetKit API
5
5
  License: MIT
6
6
  Author: Jezza34000
@@ -77,7 +77,7 @@ import asyncio
77
77
  import logging
78
78
  import aiohttp
79
79
  from pypetkitapi.client import PetKitClient
80
- from pypetkitapi.command import DeviceCommand, FeederCommand, LBCommand, LBAction, LitterCommand
80
+ from pypetkitapi.command import DeviceCommand, FeederCommand, LBCommand, DeviceAction, LitterCommand
81
81
 
82
82
  logging.basicConfig(level=logging.DEBUG)
83
83
 
@@ -86,8 +86,8 @@ async def main():
86
86
  client = PetKitClient(
87
87
  username="username", # Your PetKit account username or id
88
88
  password="password", # Your PetKit account password
89
- region="FR", # Your region or country code (e.g. FR, US, etc.)
90
- timezone="Europe/Paris", # Your timezone
89
+ region="FR", # Your region or country code (e.g. FR, US,CN etc.)
90
+ timezone="Europe/Paris", # Your timezone(e.g. "Asia/Shanghai")
91
91
  session=session,
92
92
  )
93
93
 
@@ -98,26 +98,28 @@ async def main():
98
98
  for key, value in client.petkit_entities.items():
99
99
  print(f"{key}: {type(value).__name__} - {value.name}")
100
100
 
101
+ # Select a device
102
+ device_id = key
101
103
  # Read devices or pet information
102
- print(client.petkit_entities[123456789])
104
+ print(client.petkit_entities[device_id])
103
105
 
104
106
  # Send command to the devices
105
107
  ### Example 1 : Turn on the indicator light
106
108
  ### Device_ID, Command, Payload
107
- await client.send_api_request(123456789, DeviceCommand.UPDATE_SETTING, {"lightMode": 1})
109
+ await client.send_api_request(device_id, DeviceCommand.UPDATE_SETTING, {"lightMode": 1})
108
110
 
109
111
  ### Example 2 : Feed the pet
110
112
  ### Device_ID, Command, Payload
111
113
  # simple hopper :
112
- await client.send_api_request(123456789, FeederCommand.MANUAL_FEED, {"amount": 1})
114
+ await client.send_api_request(device_id, FeederCommand.MANUAL_FEED, {"amount": 1})
113
115
  # dual hopper :
114
- await client.send_api_request(123456789, FeederCommand.MANUAL_FEED, {"amount1": 2})
116
+ await client.send_api_request(device_id, FeederCommand.MANUAL_FEED, {"amount1": 2})
115
117
  # or
116
- await client.send_api_request(123456789, FeederCommand.MANUAL_FEED, {"amount2": 2})
118
+ await client.send_api_request(device_id, FeederCommand.MANUAL_FEED, {"amount2": 2})
117
119
 
118
120
  ### Example 3 : Start the cleaning process
119
121
  ### Device_ID, Command, Payload
120
- await client.send_api_request(123456789, LitterCommand.CONTROL_DEVICE, {LBAction.START: LBCommand.CLEANING})
122
+ await client.send_api_request(device_id, LitterCommand.CONTROL_DEVICE, {DeviceAction.START: LBCommand.CLEANING})
121
123
 
122
124
 
123
125
  if __name__ == "__main__":
@@ -1,4 +1,4 @@
1
- pypetkitapi/__init__.py,sha256=shPCRXZDzB8-Pofzju8FSV6FKX8m8F_vPfW9woBu_DQ,2107
1
+ pypetkitapi/__init__.py,sha256=qDhET_P65lnwbZgZnkYst3IgJxPlID7fLqYnfVSzJqM,2107
2
2
  pypetkitapi/bluetooth.py,sha256=eu6c2h6YHBafAhhSSy4As6tn29i5WbOH9tZzRlMm44U,7843
3
3
  pypetkitapi/client.py,sha256=wzZQUHg_ee6lmdAjli6zS7qw_sgPER9iLfcTZe4VTH4,27190
4
4
  pypetkitapi/command.py,sha256=cMCUutZCQo9Ddvjl_FYR5UjU_CqFz1iyetMznYwjpzM,7500
@@ -7,13 +7,13 @@ pypetkitapi/containers.py,sha256=F_uyDBD0a5QD4s_ArjYiKTAAg1XHYBvmV_lEnO9RQ-U,478
7
7
  pypetkitapi/exceptions.py,sha256=4BXUyYXLfZjNxdnOGJPjyE9ASIl7JmQphjws87jvHtE,1631
8
8
  pypetkitapi/feeder_container.py,sha256=PhidWd5WpsZqtdKZy60PzE67YXgQfApjm8CqvMCHK3U,14743
9
9
  pypetkitapi/litter_container.py,sha256=KWvHNAOJ6hDSeJ_55tqtzY9GxHtd9gAntPkbnVbdb-I,19275
10
- pypetkitapi/media.py,sha256=BW6WHhGGn7hxdZvN27Rcg6vDu4NXB2Q_nTa8arCvacg,25687
10
+ pypetkitapi/media.py,sha256=34q3pIfejO_z-Uk8ohQlOGaPOdaGtnI0zN1LtZ3k3F4,25904
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=OjLAY6FY-g14JNJJnYMNFV5ZtdkjUzNBit1VUiiZKnQ,2053
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.11.0.dist-info/LICENSE,sha256=u5jNkZEn6YMrtN4Kr5rU3TcBJ5-eAt0qMx4JDsbsnzM,1074
17
- pypetkitapi-1.11.0.dist-info/METADATA,sha256=Xhjy59tO-gmZZodLmf6LDbu0L57IOqFgHL6CdDGfZu4,6256
18
- pypetkitapi-1.11.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
19
- pypetkitapi-1.11.0.dist-info/RECORD,,
16
+ pypetkitapi-1.11.2.dist-info/LICENSE,sha256=u5jNkZEn6YMrtN4Kr5rU3TcBJ5-eAt0qMx4JDsbsnzM,1074
17
+ pypetkitapi-1.11.2.dist-info/METADATA,sha256=8HbQJ6UeGion-oO5Y5U0X7THfeDRYeP-EK-XVwF_Lb8,6338
18
+ pypetkitapi-1.11.2.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
19
+ pypetkitapi-1.11.2.dist-info/RECORD,,