pypetkitapi 1.7.9__tar.gz → 1.8.1__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.
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/PKG-INFO +4 -2
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/README.md +2 -0
- pypetkitapi-1.8.1/pypetkitapi/__init__.py +86 -0
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/client.py +26 -16
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/command.py +32 -23
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/const.py +26 -4
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/containers.py +24 -22
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/feeder_container.py +32 -29
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/litter_container.py +30 -7
- pypetkitapi-1.8.1/pypetkitapi/purifier_container.py +77 -0
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/water_fountain_container.py +1 -2
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pyproject.toml +6 -3
- pypetkitapi-1.7.9/pypetkitapi/__init__.py +0 -1
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/LICENSE +0 -0
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/exceptions.py +0 -0
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/medias.py +0 -0
- {pypetkitapi-1.7.9 → pypetkitapi-1.8.1}/pypetkitapi/py.typed +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pypetkitapi
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.8.1
|
4
4
|
Summary: Python client for PetKit API
|
5
5
|
Home-page: https://github.com/Jezza34000/pypetkit
|
6
6
|
License: MIT
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
|
16
16
|
Requires-Dist: aiohttp (>=3.10.10,<4.0.0)
|
17
17
|
Requires-Dist: pycryptodome (>=3.19.1,<4.0.0)
|
18
|
-
Requires-Dist: pydantic (>=1.10.18,<
|
18
|
+
Requires-Dist: pydantic (>=1.10.18,<3.0.0)
|
19
19
|
Description-Content-Type: text/markdown
|
20
20
|
|
21
21
|
# Petkit API Client
|
@@ -66,6 +66,8 @@ pip install pypetkitapi
|
|
66
66
|
## Usage Example:
|
67
67
|
|
68
68
|
```python
|
69
|
+
import asyncio
|
70
|
+
import logging
|
69
71
|
import aiohttp
|
70
72
|
from pypetkitapi.client import PetKitClient
|
71
73
|
from pypetkitapi.command import DeviceCommand, FeederCommand, LBCommand, LBAction, LitterCommand
|
@@ -46,6 +46,8 @@ pip install pypetkitapi
|
|
46
46
|
## Usage Example:
|
47
47
|
|
48
48
|
```python
|
49
|
+
import asyncio
|
50
|
+
import logging
|
49
51
|
import aiohttp
|
50
52
|
from pypetkitapi.client import PetKitClient
|
51
53
|
from pypetkitapi.command import DeviceCommand, FeederCommand, LBCommand, LBAction, LitterCommand
|
@@ -0,0 +1,86 @@
|
|
1
|
+
"""Pypetkit: A Python library for interfacing with PetKit"""
|
2
|
+
|
3
|
+
from .client import PetKitClient
|
4
|
+
from .command import (
|
5
|
+
DeviceAction,
|
6
|
+
DeviceCommand,
|
7
|
+
FeederCommand,
|
8
|
+
LBCommand,
|
9
|
+
LitterCommand,
|
10
|
+
PetCommand,
|
11
|
+
PurMode,
|
12
|
+
)
|
13
|
+
from .const import (
|
14
|
+
CTW3,
|
15
|
+
D3,
|
16
|
+
D4,
|
17
|
+
D4H,
|
18
|
+
D4S,
|
19
|
+
D4SH,
|
20
|
+
DEVICES_FEEDER,
|
21
|
+
DEVICES_LITTER_BOX,
|
22
|
+
DEVICES_PURIFIER,
|
23
|
+
DEVICES_WATER_FOUNTAIN,
|
24
|
+
FEEDER,
|
25
|
+
FEEDER_MINI,
|
26
|
+
K2,
|
27
|
+
K3,
|
28
|
+
T3,
|
29
|
+
T4,
|
30
|
+
T5,
|
31
|
+
T6,
|
32
|
+
W5,
|
33
|
+
RecordType,
|
34
|
+
)
|
35
|
+
from .containers import Pet
|
36
|
+
from .exceptions import PetkitAuthenticationError, PypetkitError
|
37
|
+
from .feeder_container import Feeder, RecordsItems
|
38
|
+
from .litter_container import Litter, LitterRecord, WorkState
|
39
|
+
from .medias import MediaHandler, MediasFiles
|
40
|
+
from .purifier_container import Purifier
|
41
|
+
from .water_fountain_container import WaterFountain
|
42
|
+
|
43
|
+
__version__ = "1.8.1"
|
44
|
+
|
45
|
+
__all__ = [
|
46
|
+
"CTW3",
|
47
|
+
"D3",
|
48
|
+
"D4",
|
49
|
+
"D4H",
|
50
|
+
"D4S",
|
51
|
+
"D4SH",
|
52
|
+
"DEVICES_FEEDER",
|
53
|
+
"DEVICES_LITTER_BOX",
|
54
|
+
"DEVICES_PURIFIER",
|
55
|
+
"DEVICES_WATER_FOUNTAIN",
|
56
|
+
"DeviceAction",
|
57
|
+
"DeviceCommand",
|
58
|
+
"FEEDER",
|
59
|
+
"FEEDER_MINI",
|
60
|
+
"Feeder",
|
61
|
+
"FeederCommand",
|
62
|
+
"K2",
|
63
|
+
"K3",
|
64
|
+
"LBCommand",
|
65
|
+
"Litter",
|
66
|
+
"LitterCommand",
|
67
|
+
"LitterRecord",
|
68
|
+
"MediaHandler",
|
69
|
+
"MediasFiles",
|
70
|
+
"Pet",
|
71
|
+
"PetCommand",
|
72
|
+
"PetKitClient",
|
73
|
+
"PetkitAuthenticationError",
|
74
|
+
"PurMode",
|
75
|
+
"Purifier",
|
76
|
+
"PypetkitError",
|
77
|
+
"RecordType",
|
78
|
+
"RecordsItems",
|
79
|
+
"T3",
|
80
|
+
"T4",
|
81
|
+
"T5",
|
82
|
+
"T6",
|
83
|
+
"W5",
|
84
|
+
"WaterFountain",
|
85
|
+
"WorkState",
|
86
|
+
]
|
@@ -17,9 +17,11 @@ from pypetkitapi.const import (
|
|
17
17
|
DEVICE_STATS,
|
18
18
|
DEVICES_FEEDER,
|
19
19
|
DEVICES_LITTER_BOX,
|
20
|
+
DEVICES_PURIFIER,
|
20
21
|
DEVICES_WATER_FOUNTAIN,
|
21
22
|
ERR_KEY,
|
22
23
|
LOGIN_DATA,
|
24
|
+
PET,
|
23
25
|
RES_KEY,
|
24
26
|
T4,
|
25
27
|
T6,
|
@@ -40,6 +42,7 @@ from pypetkitapi.exceptions import (
|
|
40
42
|
)
|
41
43
|
from pypetkitapi.feeder_container import Feeder, FeederRecord
|
42
44
|
from pypetkitapi.litter_container import Litter, LitterRecord, LitterStats, PetOutGraph
|
45
|
+
from pypetkitapi.purifier_container import Purifier
|
43
46
|
from pypetkitapi.water_fountain_container import WaterFountain, WaterFountainRecord
|
44
47
|
|
45
48
|
_LOGGER = logging.getLogger(__name__)
|
@@ -50,7 +53,7 @@ class PetKitClient:
|
|
50
53
|
|
51
54
|
_session: SessionInfo | None = None
|
52
55
|
account_data: list[AccountData] = []
|
53
|
-
petkit_entities: dict[int, Feeder | Litter | WaterFountain | Pet] = {}
|
56
|
+
petkit_entities: dict[int, Feeder | Litter | WaterFountain | Purifier | Pet] = {}
|
54
57
|
|
55
58
|
def __init__(
|
56
59
|
self,
|
@@ -75,6 +78,7 @@ class PetKitClient:
|
|
75
78
|
async def _get_base_url(self) -> None:
|
76
79
|
"""Get the list of API servers, filter by region, and return the matching server."""
|
77
80
|
_LOGGER.debug("Getting API server list")
|
81
|
+
self.req.base_url = PetkitDomain.PASSPORT_PETKIT
|
78
82
|
|
79
83
|
if self.region.lower() == "china":
|
80
84
|
self.req.base_url = PetkitDomain.CHINA_SRV
|
@@ -126,8 +130,9 @@ class PetKitClient:
|
|
126
130
|
data["validCode"] = valid_code
|
127
131
|
else:
|
128
132
|
_LOGGER.debug("Login method: using password")
|
129
|
-
|
130
|
-
|
133
|
+
data["password"] = hashlib.md5(
|
134
|
+
self.password.encode()
|
135
|
+
).hexdigest() # noqa: S324
|
131
136
|
|
132
137
|
# Send the login request
|
133
138
|
response = await self.req.request(
|
@@ -149,6 +154,7 @@ class PetKitClient:
|
|
149
154
|
)
|
150
155
|
session_data = response["session"]
|
151
156
|
self._session = SessionInfo(**session_data)
|
157
|
+
self._session.refreshed_at = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
|
152
158
|
|
153
159
|
async def validate_session(self) -> None:
|
154
160
|
"""Check if the session is still valid and refresh or re-login if necessary."""
|
@@ -195,6 +201,7 @@ class PetKitClient:
|
|
195
201
|
if account.pet_list:
|
196
202
|
for pet in account.pet_list:
|
197
203
|
self.petkit_entities[pet.pet_id] = pet
|
204
|
+
pet.device_nfo = Device(deviceType=PET, deviceId=pet.pet_id)
|
198
205
|
|
199
206
|
async def get_devices_data(self) -> None:
|
200
207
|
"""Get the devices data from the PetKit servers."""
|
@@ -217,9 +224,11 @@ class PetKitClient:
|
|
217
224
|
|
218
225
|
for device in device_list:
|
219
226
|
device_type = device.device_type.lower()
|
227
|
+
|
220
228
|
if device_type in DEVICES_FEEDER:
|
221
229
|
main_tasks.append(self._fetch_device_data(device, Feeder))
|
222
230
|
record_tasks.append(self._fetch_device_data(device, FeederRecord))
|
231
|
+
|
223
232
|
elif device_type in DEVICES_LITTER_BOX:
|
224
233
|
main_tasks.append(
|
225
234
|
self._fetch_device_data(device, Litter),
|
@@ -237,6 +246,9 @@ class PetKitClient:
|
|
237
246
|
self._fetch_device_data(device, WaterFountainRecord)
|
238
247
|
)
|
239
248
|
|
249
|
+
elif device_type in DEVICES_PURIFIER:
|
250
|
+
main_tasks.append(self._fetch_device_data(device, Purifier))
|
251
|
+
|
240
252
|
# Execute main device tasks first
|
241
253
|
await asyncio.gather(*main_tasks)
|
242
254
|
|
@@ -264,6 +276,7 @@ class PetKitClient:
|
|
264
276
|
Feeder
|
265
277
|
| Litter
|
266
278
|
| WaterFountain
|
279
|
+
| Purifier
|
267
280
|
| FeederRecord
|
268
281
|
| LitterRecord
|
269
282
|
| WaterFountainRecord
|
@@ -309,15 +322,9 @@ class PetKitClient:
|
|
309
322
|
_LOGGER.error("Unexpected response type: %s", type(response))
|
310
323
|
return
|
311
324
|
|
312
|
-
# Add the device type into dataclass
|
313
|
-
if isinstance(device_data, list):
|
314
|
-
for item in device_data:
|
315
|
-
item.device_type = device_type
|
316
|
-
else:
|
317
|
-
device_data.device_type = device_type
|
318
|
-
|
319
325
|
if data_class.data_type == DEVICE_DATA:
|
320
326
|
self.petkit_entities[device.device_id] = device_data
|
327
|
+
self.petkit_entities[device.device_id].device_nfo = device
|
321
328
|
_LOGGER.debug("Device data fetched OK for %s", device_type)
|
322
329
|
elif data_class.data_type == DEVICE_RECORDS:
|
323
330
|
self.petkit_entities[device.device_id].device_records = device_data
|
@@ -358,9 +365,12 @@ class PetKitClient:
|
|
358
365
|
|
359
366
|
pets_list = await self.get_pets_list()
|
360
367
|
for pet in pets_list:
|
361
|
-
if stats_data.device_type == T4 and stats_data.device_records:
|
368
|
+
if stats_data.device_nfo.device_type == T4 and stats_data.device_records:
|
362
369
|
await self._process_t4(pet, stats_data.device_records)
|
363
|
-
elif
|
370
|
+
elif (
|
371
|
+
stats_data.device_nfo.device_type == T6
|
372
|
+
and stats_data.device_pet_graph_out
|
373
|
+
):
|
364
374
|
await self._process_t6(pet, stats_data.device_pet_graph_out)
|
365
375
|
|
366
376
|
async def _process_t4(self, pet, device_records):
|
@@ -409,15 +419,15 @@ class PetKitClient:
|
|
409
419
|
|
410
420
|
_LOGGER.debug(
|
411
421
|
"Control API device=%s id=%s action=%s param=%s",
|
412
|
-
device.device_type,
|
422
|
+
device.device_nfo.device_type,
|
413
423
|
device_id,
|
414
424
|
action,
|
415
425
|
setting,
|
416
426
|
)
|
417
427
|
|
418
428
|
# Check if the device type is supported
|
419
|
-
if device.device_type:
|
420
|
-
device_type = device.device_type.lower()
|
429
|
+
if device.device_nfo.device_type:
|
430
|
+
device_type = device.device_nfo.device_type.lower()
|
421
431
|
else:
|
422
432
|
raise PypetkitError(
|
423
433
|
"Device type is not available, and is mandatory for sending commands."
|
@@ -442,7 +452,7 @@ class PetKitClient:
|
|
442
452
|
else:
|
443
453
|
endpoint = action_info.endpoint
|
444
454
|
_LOGGER.debug("Endpoint field")
|
445
|
-
url = f"{device.device_type.lower()}/{endpoint}"
|
455
|
+
url = f"{device.device_nfo.device_type.lower()}/{endpoint}"
|
446
456
|
|
447
457
|
# Get the parameters
|
448
458
|
if setting is not None:
|
@@ -16,6 +16,8 @@ from pypetkitapi.const import (
|
|
16
16
|
DEVICES_FEEDER,
|
17
17
|
FEEDER,
|
18
18
|
FEEDER_MINI,
|
19
|
+
K2,
|
20
|
+
K3,
|
19
21
|
T3,
|
20
22
|
T4,
|
21
23
|
T5,
|
@@ -27,11 +29,13 @@ from pypetkitapi.const import (
|
|
27
29
|
class DeviceCommand(StrEnum):
|
28
30
|
"""Device Command"""
|
29
31
|
|
32
|
+
POWER = "power_device"
|
33
|
+
CONTROL_DEVICE = "control_device"
|
30
34
|
UPDATE_SETTING = "update_setting"
|
31
35
|
|
32
36
|
|
33
37
|
class FeederCommand(StrEnum):
|
34
|
-
"""Feeder Command"""
|
38
|
+
"""Specific Feeder Command"""
|
35
39
|
|
36
40
|
CALL_PET = "call_pet"
|
37
41
|
CALIBRATION = "food_reset"
|
@@ -45,25 +49,17 @@ class FeederCommand(StrEnum):
|
|
45
49
|
|
46
50
|
|
47
51
|
class LitterCommand(StrEnum):
|
48
|
-
"""LitterCommand"""
|
52
|
+
"""Specific LitterCommand"""
|
49
53
|
|
50
|
-
POWER = "power"
|
51
|
-
CONTROL_DEVICE = "control_device"
|
52
54
|
RESET_DEODORIZER = "reset_deodorizer"
|
53
55
|
|
54
56
|
|
55
57
|
class PetCommand(StrEnum):
|
56
|
-
"""PetCommand"""
|
58
|
+
"""Specific PetCommand"""
|
57
59
|
|
58
60
|
PET_UPDATE_SETTING = "pet_update_setting"
|
59
61
|
|
60
62
|
|
61
|
-
class FountainCommand(StrEnum):
|
62
|
-
"""Fountain Command"""
|
63
|
-
|
64
|
-
CONTROL_DEVICE = "control_device"
|
65
|
-
|
66
|
-
|
67
63
|
class LBCommand(IntEnum):
|
68
64
|
"""LitterBoxCommand"""
|
69
65
|
|
@@ -79,14 +75,27 @@ class LBCommand(IntEnum):
|
|
79
75
|
MAINTENANCE = 9
|
80
76
|
|
81
77
|
|
82
|
-
class
|
83
|
-
"""
|
78
|
+
class PurMode(IntEnum):
|
79
|
+
"""Purifier working mode"""
|
80
|
+
|
81
|
+
AUTO_MODE = 0
|
82
|
+
SILENT_MODE = 1
|
83
|
+
STANDARD_MODE = 2
|
84
|
+
STRONG_MODE = 3
|
84
85
|
|
86
|
+
|
87
|
+
class DeviceAction(StrEnum):
|
88
|
+
"""Device action for LitterBox and Purifier"""
|
89
|
+
|
90
|
+
# LitterBox only
|
85
91
|
CONTINUE = "continue_action"
|
86
92
|
END = "end_action"
|
87
|
-
POWER = "power_action"
|
88
93
|
START = "start_action"
|
89
94
|
STOP = "stop_action"
|
95
|
+
# Purifier only
|
96
|
+
MODE = "mode_action"
|
97
|
+
# All devices
|
98
|
+
POWER = "power_action"
|
90
99
|
|
91
100
|
|
92
101
|
class FountainAction(StrEnum):
|
@@ -162,6 +171,15 @@ ACTIONS_MAP = {
|
|
162
171
|
},
|
163
172
|
supported_device=ALL_DEVICES,
|
164
173
|
),
|
174
|
+
DeviceCommand.CONTROL_DEVICE: CmdData(
|
175
|
+
endpoint=PetkitEndpoint.CONTROL_DEVICE,
|
176
|
+
params=lambda device, command: {
|
177
|
+
"id": device.id,
|
178
|
+
"kv": json.dumps(command),
|
179
|
+
"type": list(command.keys())[0].split("_")[0],
|
180
|
+
},
|
181
|
+
supported_device=[K2, K3, T3, T4, T5, T6],
|
182
|
+
),
|
165
183
|
FeederCommand.REMOVE_DAILY_FEED: CmdData(
|
166
184
|
endpoint=PetkitEndpoint.REMOVE_DAILY_FEED,
|
167
185
|
params=lambda device, setting: {
|
@@ -255,15 +273,6 @@ ACTIONS_MAP = {
|
|
255
273
|
},
|
256
274
|
supported_device=[D3],
|
257
275
|
),
|
258
|
-
LitterCommand.CONTROL_DEVICE: CmdData(
|
259
|
-
endpoint=PetkitEndpoint.CONTROL_DEVICE,
|
260
|
-
params=lambda device, command: {
|
261
|
-
"id": device.id,
|
262
|
-
"kv": json.dumps(command),
|
263
|
-
"type": list(command.keys())[0].split("_")[0],
|
264
|
-
},
|
265
|
-
supported_device=[T3, T4, T5, T6],
|
266
|
-
),
|
267
276
|
PetCommand.PET_UPDATE_SETTING: CmdData(
|
268
277
|
endpoint=PetkitEndpoint.CONTROL_DEVICE,
|
269
278
|
params=lambda pet, setting: {
|
@@ -2,9 +2,6 @@
|
|
2
2
|
|
3
3
|
from enum import StrEnum
|
4
4
|
|
5
|
-
MIN_FEED_AMOUNT = 0
|
6
|
-
MAX_FEED_AMOUNT = 10
|
7
|
-
|
8
5
|
RES_KEY = "result"
|
9
6
|
ERR_KEY = "error"
|
10
7
|
SUCCESS_KEY = "success"
|
@@ -29,11 +26,19 @@ T6 = "t6"
|
|
29
26
|
W5 = "w5"
|
30
27
|
CTW3 = "ctw3"
|
31
28
|
K2 = "k2"
|
29
|
+
K3 = "k3"
|
30
|
+
PET = "pet"
|
32
31
|
|
33
32
|
DEVICES_LITTER_BOX = [T3, T4, T5, T6]
|
34
33
|
DEVICES_FEEDER = [FEEDER, FEEDER_MINI, D3, D4, D4S, D4H, D4SH]
|
35
34
|
DEVICES_WATER_FOUNTAIN = [W5, CTW3]
|
36
|
-
|
35
|
+
DEVICES_PURIFIER = [K2]
|
36
|
+
ALL_DEVICES = [
|
37
|
+
*DEVICES_LITTER_BOX,
|
38
|
+
*DEVICES_FEEDER,
|
39
|
+
*DEVICES_WATER_FOUNTAIN,
|
40
|
+
*DEVICES_PURIFIER,
|
41
|
+
]
|
37
42
|
|
38
43
|
|
39
44
|
class PetkitDomain(StrEnum):
|
@@ -86,6 +91,18 @@ LOGIN_DATA = {
|
|
86
91
|
}
|
87
92
|
|
88
93
|
|
94
|
+
class RecordType(StrEnum):
|
95
|
+
"""Record Type constants"""
|
96
|
+
|
97
|
+
EAT = "eat"
|
98
|
+
FEED = "feed"
|
99
|
+
MOVE = "move"
|
100
|
+
PET = "pet"
|
101
|
+
|
102
|
+
|
103
|
+
RecordTypeLST = [RecordType.EAT, RecordType.FEED, RecordType.MOVE, RecordType.PET]
|
104
|
+
|
105
|
+
|
89
106
|
class PetkitEndpoint(StrEnum):
|
90
107
|
"""Petkit Endpoint constants"""
|
91
108
|
|
@@ -119,6 +136,11 @@ class PetkitEndpoint(StrEnum):
|
|
119
136
|
STATISTIC_RELEASE = "statisticRelease"
|
120
137
|
GET_PET_OUT_GRAPH = "getPetOutGraph"
|
121
138
|
|
139
|
+
# Video features
|
140
|
+
CLOUD_VIDEO = "cloud/video"
|
141
|
+
GET_DOWNLOAD_M3U8 = "getDownloadM3u8"
|
142
|
+
GET_M3U8 = "getM3u8"
|
143
|
+
|
122
144
|
# Feeders
|
123
145
|
REPLENISHED_FOOD = "added"
|
124
146
|
FRESH_ELEMENT_CALIBRATION = "food_reset"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Dataclasses container for petkit API."""
|
2
2
|
|
3
|
-
from pydantic import BaseModel, Field
|
3
|
+
from pydantic import BaseModel, Field
|
4
4
|
|
5
5
|
|
6
6
|
class RegionInfo(BaseModel):
|
@@ -43,6 +43,7 @@ class SessionInfo(BaseModel):
|
|
43
43
|
expires_in: int = Field(alias="expiresIn")
|
44
44
|
region: str | None = None
|
45
45
|
created_at: str = Field(alias="createdAt")
|
46
|
+
refreshed_at: str | None = None
|
46
47
|
|
47
48
|
|
48
49
|
class Device(BaseModel):
|
@@ -50,14 +51,14 @@ class Device(BaseModel):
|
|
50
51
|
Subclass of AccountData.
|
51
52
|
"""
|
52
53
|
|
53
|
-
created_at: int = Field(alias="createdAt")
|
54
|
-
device_id: int = Field(alias="deviceId")
|
55
|
-
device_name: str = Field(alias="deviceName")
|
56
|
-
device_type: str = Field(alias="deviceType")
|
57
|
-
group_id: int = Field(alias="groupId")
|
58
|
-
type: int
|
59
|
-
type_code: int = Field(alias="typeCode")
|
60
|
-
unique_id: str = Field(alias="uniqueId")
|
54
|
+
created_at: int | None = Field(None, alias="createdAt")
|
55
|
+
device_id: int | None = Field(None, alias="deviceId")
|
56
|
+
device_name: str | None = Field(None, alias="deviceName")
|
57
|
+
device_type: str | None = Field(None, alias="deviceType")
|
58
|
+
group_id: int | None = Field(None, alias="groupId")
|
59
|
+
type: int | None = None
|
60
|
+
type_code: int = Field(0, alias="typeCode")
|
61
|
+
unique_id: str | None = Field(None, alias="uniqueId")
|
61
62
|
|
62
63
|
|
63
64
|
class Pet(BaseModel):
|
@@ -69,25 +70,26 @@ class Pet(BaseModel):
|
|
69
70
|
created_at: int = Field(alias="createdAt")
|
70
71
|
pet_id: int = Field(alias="petId")
|
71
72
|
pet_name: str | None = Field(None, alias="petName")
|
72
|
-
id: int | None = None # Fictive field (for HA compatibility)
|
73
|
-
sn: str # Fictive field (for HA compatibility)
|
74
|
-
name: str | None = None # Fictive field (for HA compatibility)
|
75
|
-
|
76
|
-
|
73
|
+
id: int | None = None # Fictive field copied from id (for HA compatibility)
|
74
|
+
sn: str | None = None # Fictive field copied from id (for HA compatibility)
|
75
|
+
name: str | None = None # Fictive field copied from pet_name (for HA compatibility)
|
76
|
+
firmware: str | None = None # Fictive fixed field (for HA compatibility)
|
77
|
+
device_nfo: Device = Field(default_factory=Device)
|
77
78
|
|
78
|
-
#
|
79
|
+
# Litter stats
|
79
80
|
last_litter_usage: int = 0
|
80
81
|
last_device_used: str | None = None
|
81
82
|
last_duration_usage: int = 0
|
82
83
|
last_measured_weight: int = 0
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
85
|
+
def __init__(self, **data):
|
86
|
+
"""Initialize the Pet dataclass.
|
87
|
+
This method is used to fill the fictive fields after the standard initialization.
|
88
|
+
"""
|
89
|
+
super().__init__(**data)
|
90
|
+
self.id = self.id or self.pet_id
|
91
|
+
self.sn = self.sn or str(self.id)
|
92
|
+
self.name = self.name or self.pet_name
|
91
93
|
|
92
94
|
|
93
95
|
class User(BaseModel):
|
@@ -12,12 +12,12 @@ from pypetkitapi.containers import CloudProduct, Device, FirmwareDetail, Wifi
|
|
12
12
|
class FeedItem(BaseModel):
|
13
13
|
"""Dataclass for feed item data."""
|
14
14
|
|
15
|
-
id: str | None = None
|
16
|
-
name: str | None = None
|
17
|
-
time: int | None = None
|
18
15
|
amount: int | None = None
|
19
16
|
amount1: int | None = Field(None, alias="amount1")
|
20
17
|
amount2: int | None = Field(None, alias="amount2")
|
18
|
+
id: str | None = None
|
19
|
+
name: str | None = None
|
20
|
+
time: int | None = None
|
21
21
|
|
22
22
|
|
23
23
|
class FeedDailyList(BaseModel):
|
@@ -50,9 +50,14 @@ class SettingsFeeder(BaseModel):
|
|
50
50
|
attire_id: int | None = Field(None, alias="attireId")
|
51
51
|
attire_switch: int | None = Field(None, alias="attireSwitch")
|
52
52
|
auto_product: int | None = Field(None, alias="autoProduct")
|
53
|
+
bucket_name1: str | None = Field(None, alias="bucketName1")
|
54
|
+
bucket_name2: str | None = Field(None, alias="bucketName2")
|
53
55
|
camera: int | None = None
|
54
56
|
camera_config: int | None = Field(None, alias="cameraConfig")
|
57
|
+
camera_multi_new: list[CameraMultiNew] | None = Field(None, alias="cameraMultiNew")
|
55
58
|
camera_multi_range: list | None = Field(None, alias="cameraMultiRange")
|
59
|
+
color_setting: int | None = None
|
60
|
+
conservation: int | None = None
|
56
61
|
control_settings: int | None = Field(None, alias="controlSettings")
|
57
62
|
desiccant_notify: int | None = Field(None, alias="desiccantNotify")
|
58
63
|
detect_config: int | None = Field(None, alias="detectConfig")
|
@@ -62,8 +67,10 @@ class SettingsFeeder(BaseModel):
|
|
62
67
|
eat_notify: int | None = Field(None, alias="eatNotify")
|
63
68
|
eat_sensitivity: int | None = Field(None, alias="eatSensitivity")
|
64
69
|
eat_video: int | None = Field(None, alias="eatVideo")
|
70
|
+
factor: int | None = None
|
65
71
|
feed_notify: int | None = Field(None, alias="feedNotify")
|
66
72
|
feed_picture: int | None = Field(None, alias="feedPicture")
|
73
|
+
feed_sound: int | None = Field(None, alias="feedSound")
|
67
74
|
food_notify: int | None = Field(None, alias="foodNotify")
|
68
75
|
food_warn: int | None = Field(None, alias="foodWarn")
|
69
76
|
food_warn_range: list[int] | None = Field(None, alias="foodWarnRange")
|
@@ -87,6 +94,7 @@ class SettingsFeeder(BaseModel):
|
|
87
94
|
pet_sensitivity: int | None = Field(None, alias="petSensitivity")
|
88
95
|
pre_live: int | None = Field(None, alias="preLive")
|
89
96
|
selected_sound: int | None = Field(None, alias="selectedSound")
|
97
|
+
shortest: int | None = None # D4S
|
90
98
|
smart_frame: int | None = Field(None, alias="smartFrame")
|
91
99
|
sound_enable: int | None = Field(None, alias="soundEnable")
|
92
100
|
surplus: int | None = None # D3
|
@@ -99,35 +107,29 @@ class SettingsFeeder(BaseModel):
|
|
99
107
|
tone_multi_range: list[tuple[int, int]] | None = Field(None, alias="toneMultiRange")
|
100
108
|
upload: int | None = None
|
101
109
|
volume: int | None = None
|
102
|
-
feed_sound: int | None = Field(None, alias="feedSound")
|
103
|
-
factor: int | None = None
|
104
|
-
color_setting: int | None = Field(None, alias="colorSetting")
|
105
|
-
conservation: int | None = None
|
106
|
-
bucket_name1: str | None = Field(None, alias="bucketName1")
|
107
|
-
bucket_name2: str | None = Field(None, alias="bucketName2")
|
108
|
-
camera_multi_new: list[CameraMultiNew] | None = Field(None, alias="cameraMultiNew")
|
109
110
|
|
110
111
|
|
111
112
|
class FeedState(BaseModel):
|
112
113
|
"""Dataclass for feed state data."""
|
113
114
|
|
115
|
+
add_amount_total: int | None = Field(None, alias="addAmountTotal")
|
116
|
+
add_amount_total1: int | None = Field(None, alias="addAmountTotal1")
|
117
|
+
add_amount_total2: int | None = Field(None, alias="addAmountTotal2")
|
118
|
+
eat_amount_total: int | None = Field(None, alias="eatAmountTotal") # D3
|
114
119
|
eat_avg: int | None = Field(None, alias="eatAvg")
|
115
120
|
eat_count: int | None = Field(None, alias="eatCount")
|
116
121
|
eat_times: list[int] | None = Field(None, alias="eatTimes")
|
117
122
|
feed_times: dict | list | None = Field(None, alias="feedTimes")
|
118
|
-
times: int | None = None
|
119
|
-
add_amount_total: int | None = Field(None, alias="addAmountTotal")
|
120
123
|
plan_amount_total: int | None = Field(None, alias="planAmountTotal")
|
121
|
-
plan_real_amount_total: int | None = Field(None, alias="planRealAmountTotal")
|
122
|
-
real_amount_total: int | None = Field(None, alias="realAmountTotal")
|
123
|
-
add_amount_total1: int | None = Field(None, alias="addAmountTotal1")
|
124
|
-
add_amount_total2: int | None = Field(None, alias="addAmountTotal2")
|
125
124
|
plan_amount_total1: int | None = Field(None, alias="planAmountTotal1")
|
126
125
|
plan_amount_total2: int | None = Field(None, alias="planAmountTotal2")
|
126
|
+
plan_real_amount_total: int | None = Field(None, alias="planRealAmountTotal")
|
127
127
|
plan_real_amount_total1: int | None = Field(None, alias="planRealAmountTotal1")
|
128
128
|
plan_real_amount_total2: int | None = Field(None, alias="planRealAmountTotal2")
|
129
|
+
real_amount_total: int | None = Field(None, alias="realAmountTotal")
|
129
130
|
real_amount_total1: int | None = Field(None, alias="realAmountTotal1")
|
130
131
|
real_amount_total2: int | None = Field(None, alias="realAmountTotal2")
|
132
|
+
times: int | None = None
|
131
133
|
|
132
134
|
|
133
135
|
class StateFeeder(BaseModel):
|
@@ -135,31 +137,31 @@ class StateFeeder(BaseModel):
|
|
135
137
|
|
136
138
|
battery_power: int | None = Field(None, alias="batteryPower")
|
137
139
|
battery_status: int | None = Field(None, alias="batteryStatus")
|
138
|
-
bowl: int | None = None
|
139
140
|
block: int | None = None
|
141
|
+
bowl: int | None = None
|
140
142
|
broadcast: dict | None = None
|
141
143
|
camera_status: int | None = Field(None, alias="cameraStatus")
|
142
144
|
charge: int | None = None
|
145
|
+
conservation_status: int | None = Field(None, alias="conservationStatus")
|
143
146
|
desiccant_left_days: int | None = Field(None, alias="desiccantLeftDays")
|
144
147
|
desiccant_time: int | None = Field(None, alias="desiccantTime")
|
145
148
|
door: int | None = None
|
146
|
-
|
147
|
-
feeding: int | None = None
|
149
|
+
eating: int | None = None
|
148
150
|
error_code: str | None = Field(None, alias="errorCode")
|
149
151
|
error_detail: str | None = Field(None, alias="errorDetail")
|
150
152
|
error_level: int | None = Field(None, alias="errorLevel")
|
151
153
|
error_msg: str | None = Field(None, alias="errorMsg")
|
154
|
+
feed_state: FeedState | None = Field(None, alias="feedState")
|
155
|
+
feeding: int | None = None
|
156
|
+
food: int | None = None
|
157
|
+
food1: int | None = Field(None, alias="food1")
|
158
|
+
food2: int | None = Field(None, alias="food2")
|
152
159
|
ota: int | None = None
|
153
160
|
overall: int | None = None
|
154
161
|
pim: int | None = None
|
155
162
|
runtime: int | None = None
|
156
163
|
weight: int | None = None
|
157
164
|
wifi: Wifi | None = None
|
158
|
-
eating: int | None = None
|
159
|
-
food: int | None = None
|
160
|
-
food1: int | None = Field(None, alias="food1")
|
161
|
-
food2: int | None = Field(None, alias="food2")
|
162
|
-
conservation_status: int | None = Field(None, alias="conservationStatus")
|
163
165
|
|
164
166
|
|
165
167
|
class ManualFeed(BaseModel):
|
@@ -265,6 +267,7 @@ class FeederRecord(BaseModel):
|
|
265
267
|
move: list[RecordsType] | None = None
|
266
268
|
pet: list[RecordsType] | None = None
|
267
269
|
device_type: str | None = Field(None, alias="deviceType")
|
270
|
+
type_code: int = Field(0, alias="typeCode")
|
268
271
|
|
269
272
|
@classmethod
|
270
273
|
def get_endpoint(cls, device_type: str) -> str | None:
|
@@ -302,15 +305,19 @@ class Feeder(BaseModel):
|
|
302
305
|
bt_mac: str | None = Field(None, alias="btMac")
|
303
306
|
cloud_product: CloudProduct | None = Field(None, alias="cloudProduct")
|
304
307
|
created_at: str | None = Field(None, alias="createdAt")
|
308
|
+
device_records: FeederRecord | None = None
|
305
309
|
firmware: float
|
306
310
|
firmware_details: list[FirmwareDetail] | None = Field(None, alias="firmwareDetails")
|
307
311
|
hardware: int
|
308
312
|
id: int
|
309
313
|
locale: str | None = None
|
310
314
|
mac: str | None = None
|
315
|
+
manual_feed: ManualFeed | None = None
|
311
316
|
model_code: int | None = Field(None, alias="modelCode")
|
317
|
+
multi_config: bool | None = Field(None, alias="multiConfig")
|
312
318
|
multi_feed_item: MultiFeedItem | None = Field(None, alias="multiFeedItem")
|
313
319
|
name: str | None = None
|
320
|
+
p2p_type: int | None = Field(None, alias="p2pType")
|
314
321
|
secret: str | None = None
|
315
322
|
service_status: int | None = Field(None, alias="serviceStatus")
|
316
323
|
settings: SettingsFeeder | None = None
|
@@ -319,11 +326,7 @@ class Feeder(BaseModel):
|
|
319
326
|
sn: str
|
320
327
|
state: StateFeeder | None = None
|
321
328
|
timezone: float | None = None
|
322
|
-
|
323
|
-
multi_config: bool | None = Field(None, alias="multiConfig")
|
324
|
-
device_type: str | None = Field(None, alias="deviceType")
|
325
|
-
manual_feed: ManualFeed | None = None
|
326
|
-
device_records: FeederRecord | None = None
|
329
|
+
device_nfo: Device | None = None
|
327
330
|
|
328
331
|
@classmethod
|
329
332
|
def get_endpoint(cls, device_type: str) -> str:
|
@@ -10,6 +10,7 @@ from pypetkitapi.const import (
|
|
10
10
|
DEVICE_RECORDS,
|
11
11
|
DEVICE_STATS,
|
12
12
|
T4,
|
13
|
+
T5,
|
13
14
|
T6,
|
14
15
|
PetkitEndpoint,
|
15
16
|
)
|
@@ -77,7 +78,6 @@ class SettingsLitter(BaseModel):
|
|
77
78
|
pet_detection: int | None = Field(None, alias="petDetection")
|
78
79
|
pet_notify: int | None = Field(None, alias="petNotify")
|
79
80
|
pre_live: int | None = Field(None, alias="preLive")
|
80
|
-
shortest: int | None = None
|
81
81
|
system_sound_enable: int | None = Field(None, alias="systemSoundEnable")
|
82
82
|
time_display: int | None = Field(None, alias="timeDisplay")
|
83
83
|
toilet_detection: int | None = Field(None, alias="toiletDetection")
|
@@ -235,14 +235,13 @@ class LitterRecord(BaseModel):
|
|
235
235
|
toilet_detection: int | None = Field(None, alias="toiletDetection")
|
236
236
|
upload: int | None = None
|
237
237
|
user_id: str | None = Field(None, alias="userId")
|
238
|
-
device_type: str | None = Field(None, alias="deviceType")
|
239
238
|
|
240
239
|
@classmethod
|
241
240
|
def get_endpoint(cls, device_type: str) -> str:
|
242
241
|
"""Get the endpoint URL for the given device type."""
|
243
242
|
if device_type == T4:
|
244
243
|
return PetkitEndpoint.GET_DEVICE_RECORD
|
245
|
-
if device_type
|
244
|
+
if device_type in [T5, T6]:
|
246
245
|
return PetkitEndpoint.GET_DEVICE_RECORD_RELEASE
|
247
246
|
raise ValueError(f"Invalid device type: {device_type}")
|
248
247
|
|
@@ -259,7 +258,7 @@ class LitterRecord(BaseModel):
|
|
259
258
|
if request_date is None:
|
260
259
|
request_date = datetime.now().strftime("%Y%m%d")
|
261
260
|
return {"date": int(request_date), "deviceId": device.device_id}
|
262
|
-
if device_type
|
261
|
+
if device_type in [T5, T6]:
|
263
262
|
return {
|
264
263
|
"timestamp": int(datetime.now().timestamp()),
|
265
264
|
"deviceId": device.device_id,
|
@@ -295,7 +294,6 @@ class LitterStats(BaseModel):
|
|
295
294
|
statistic_time: str | None = Field(None, alias="statisticTime")
|
296
295
|
times: int | None = None
|
297
296
|
total_time: int | None = Field(None, alias="totalTime")
|
298
|
-
device_type: str | None = None
|
299
297
|
|
300
298
|
@classmethod
|
301
299
|
def get_endpoint(cls, device_type: str) -> str:
|
@@ -359,7 +357,6 @@ class PetOutGraph(BaseModel):
|
|
359
357
|
storage_space: int | None = Field(None, alias="storageSpace")
|
360
358
|
time: int | None = None
|
361
359
|
toilet_time: int | None = Field(None, alias="toiletTime")
|
362
|
-
device_type: str | None = None
|
363
360
|
|
364
361
|
@classmethod
|
365
362
|
def get_endpoint(cls, device_type: str) -> str:
|
@@ -382,6 +379,31 @@ class PetOutGraph(BaseModel):
|
|
382
379
|
}
|
383
380
|
|
384
381
|
|
382
|
+
class K3Device(BaseModel):
|
383
|
+
"""Dataclass for K3 device data."""
|
384
|
+
|
385
|
+
battery: int | None = None
|
386
|
+
created_at: datetime | None = Field(None, alias="createdAt")
|
387
|
+
firmware: int | None = None
|
388
|
+
hardware: int | None = None
|
389
|
+
id: int | None = None
|
390
|
+
lighting: int | None = None
|
391
|
+
liquid: int | None = None
|
392
|
+
liquid_lack: int | None = Field(None, alias="liquidLack")
|
393
|
+
mac: str | None = None
|
394
|
+
name: str | None = None
|
395
|
+
refreshing: int | None = None
|
396
|
+
relate_t4: int | None = Field(None, alias="relateT4")
|
397
|
+
relation: dict | None = None
|
398
|
+
secret: str | None = None
|
399
|
+
settings: dict | None = None
|
400
|
+
sn: str | None = None
|
401
|
+
timezone: float | None = None
|
402
|
+
update_at: datetime | None = Field(None, alias="updateAt")
|
403
|
+
user_id: str | None = Field(None, alias="userId")
|
404
|
+
voltage: int | None = None
|
405
|
+
|
406
|
+
|
385
407
|
class Litter(BaseModel):
|
386
408
|
"""Dataclass for Litter Data.
|
387
409
|
Supported devices = T3, T4, T6
|
@@ -396,6 +418,7 @@ class Litter(BaseModel):
|
|
396
418
|
firmware_details: list[FirmwareDetail] = Field(alias="firmwareDetails")
|
397
419
|
hardware: int
|
398
420
|
id: int
|
421
|
+
k3_device: K3Device | None = Field(None, alias="k3Device")
|
399
422
|
is_pet_out_tips: int | None = Field(None, alias="isPetOutTips")
|
400
423
|
locale: str | None = None
|
401
424
|
mac: str | None = None
|
@@ -422,10 +445,10 @@ class Litter(BaseModel):
|
|
422
445
|
service_status: int | None = Field(None, alias="serviceStatus")
|
423
446
|
total_time: int | None = Field(None, alias="totalTime")
|
424
447
|
with_k3: int | None = Field(None, alias="withK3")
|
425
|
-
device_type: str | None = Field(None, alias="deviceType")
|
426
448
|
device_records: list[LitterRecord] | None = None
|
427
449
|
device_stats: LitterStats | None = None
|
428
450
|
device_pet_graph_out: list[PetOutGraph] | None = None
|
451
|
+
device_nfo: Device | None = None
|
429
452
|
|
430
453
|
@classmethod
|
431
454
|
def get_endpoint(cls, device_type: str) -> str:
|
@@ -0,0 +1,77 @@
|
|
1
|
+
"""Dataclasses for feeder data."""
|
2
|
+
|
3
|
+
from typing import Any, ClassVar
|
4
|
+
|
5
|
+
from pydantic import BaseModel, Field
|
6
|
+
|
7
|
+
from pypetkitapi.const import DEVICE_DATA, PetkitEndpoint
|
8
|
+
from pypetkitapi.containers import Device, FirmwareDetail, Wifi
|
9
|
+
|
10
|
+
|
11
|
+
class Settings(BaseModel):
|
12
|
+
"""Dataclass for settings data."""
|
13
|
+
|
14
|
+
auto_work: int | None = Field(None, alias="autoWork")
|
15
|
+
lack_notify: int | None = Field(None, alias="lackNotify")
|
16
|
+
light_mode: int | None = Field(None, alias="lightMode")
|
17
|
+
light_range: list[int] | None = Field(None, alias="lightRange")
|
18
|
+
log_notify: int | None = Field(None, alias="logNotify")
|
19
|
+
manual_lock: int | None = Field(None, alias="manualLock")
|
20
|
+
sound: int | None = None
|
21
|
+
temp_unit: int | None = Field(None, alias="tempUnit")
|
22
|
+
|
23
|
+
|
24
|
+
class State(BaseModel):
|
25
|
+
"""Dataclass for state data."""
|
26
|
+
|
27
|
+
humidity: int | None = None
|
28
|
+
left_day: int | None = Field(None, alias="leftDay")
|
29
|
+
liquid: int | None = None
|
30
|
+
mode: int | None = None
|
31
|
+
ota: int | None = None
|
32
|
+
overall: int | None = None
|
33
|
+
pim: int | None = None
|
34
|
+
power: int | None = None
|
35
|
+
refresh: float | None = None
|
36
|
+
temp: int | None = None
|
37
|
+
wifi: Wifi | None = None
|
38
|
+
|
39
|
+
|
40
|
+
class Purifier(BaseModel):
|
41
|
+
"""Dataclass for feeder data."""
|
42
|
+
|
43
|
+
data_type: ClassVar[str] = DEVICE_DATA
|
44
|
+
|
45
|
+
bt_mac: str | None = Field(None, alias="btMac")
|
46
|
+
created_at: str | None = Field(None, alias="createdAt")
|
47
|
+
firmware: str | None = None
|
48
|
+
firmware_details: list[FirmwareDetail] | None = Field(None, alias="firmwareDetails")
|
49
|
+
hardware: int | None = None
|
50
|
+
id: int | None = None
|
51
|
+
locale: str | None = None
|
52
|
+
mac: str | None = None
|
53
|
+
name: str | None = None
|
54
|
+
relation: dict[str, str]
|
55
|
+
secret: str | None = None
|
56
|
+
settings: Settings | None = None
|
57
|
+
share_open: int | None = Field(None, alias="shareOpen")
|
58
|
+
signup_at: str | None = Field(None, alias="signupAt")
|
59
|
+
sn: str | None = None
|
60
|
+
state: State | None = None
|
61
|
+
timezone: float | None = None
|
62
|
+
work_time: list[tuple[int, int]] | None = Field(None, alias="workTime")
|
63
|
+
device_nfo: Device | None = None
|
64
|
+
|
65
|
+
@classmethod
|
66
|
+
def get_endpoint(cls, device_type: str) -> str:
|
67
|
+
"""Get the endpoint URL for the given device type."""
|
68
|
+
return PetkitEndpoint.DEVICE_DETAIL
|
69
|
+
|
70
|
+
@classmethod
|
71
|
+
def query_param(
|
72
|
+
cls,
|
73
|
+
device: Device,
|
74
|
+
device_data: Any | None = None,
|
75
|
+
) -> dict:
|
76
|
+
"""Generate query parameters including request_date."""
|
77
|
+
return {"id": int(device.device_id)}
|
@@ -93,7 +93,6 @@ class WaterFountainRecord(BaseModel):
|
|
93
93
|
day_time: int | None = Field(None, alias="dayTime")
|
94
94
|
stay_time: int | None = Field(None, alias="stayTime")
|
95
95
|
work_time: int | None = Field(None, alias="workTime")
|
96
|
-
device_type: str | None = Field(None, alias="deviceType")
|
97
96
|
|
98
97
|
@classmethod
|
99
98
|
def get_endpoint(cls, device_type: str) -> str | None:
|
@@ -163,8 +162,8 @@ class WaterFountain(BaseModel):
|
|
163
162
|
update_at: str | None = Field(None, alias="updateAt")
|
164
163
|
user_id: str | None = Field(None, alias="userId")
|
165
164
|
water_pump_run_time: int | None = Field(None, alias="waterPumpRunTime")
|
166
|
-
device_type: str | None = Field(None, alias="deviceType")
|
167
165
|
device_records: list[WaterFountainRecord] | None = None
|
166
|
+
device_nfo: Device | None = None
|
168
167
|
|
169
168
|
@classmethod
|
170
169
|
def get_endpoint(cls, device_type: str) -> str:
|
@@ -187,7 +187,7 @@ build-backend = "poetry.core.masonry.api"
|
|
187
187
|
|
188
188
|
[tool.poetry]
|
189
189
|
name = "pypetkitapi"
|
190
|
-
version = "1.
|
190
|
+
version = "1.8.1"
|
191
191
|
description = "Python client for PetKit API"
|
192
192
|
authors = ["Jezza34000 <info@mail.com>"]
|
193
193
|
readme = "README.md"
|
@@ -199,7 +199,7 @@ python = ">=3.11"
|
|
199
199
|
aiohttp = "^3.10.10"
|
200
200
|
aiofiles = "^24.1.0"
|
201
201
|
pycryptodome = "^3.19.1"
|
202
|
-
pydantic = "
|
202
|
+
pydantic = ">=1.10.18,<3.0.0"
|
203
203
|
|
204
204
|
[tool.poetry.dev-dependencies]
|
205
205
|
pre-commit = "^4.0.1"
|
@@ -208,7 +208,7 @@ ruff = "^0.8.1"
|
|
208
208
|
types-aiofiles = "^24.1.0.20240626"
|
209
209
|
|
210
210
|
[tool.bumpver]
|
211
|
-
current_version = "1.
|
211
|
+
current_version = "1.8.1"
|
212
212
|
version_pattern = "MAJOR.MINOR.PATCH"
|
213
213
|
commit_message = "bump version {old_version} -> {new_version}"
|
214
214
|
tag_message = "{new_version}"
|
@@ -224,6 +224,9 @@ push = true
|
|
224
224
|
'^version = "{version}"',
|
225
225
|
'^current_version = "{version}"',
|
226
226
|
]
|
227
|
+
"pypetkitapi/__init__.py" = [
|
228
|
+
'^__version__ = "{version}"',
|
229
|
+
]
|
227
230
|
|
228
231
|
[tool.tox]
|
229
232
|
envlist = ["pre-commit"]
|
@@ -1 +0,0 @@
|
|
1
|
-
"""Pypetkit: A Python library for interfacing with PetKit"""
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|