pypetkitapi 0.1.2__py3-none-any.whl → 0.2.1__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/client.py +33 -12
- pypetkitapi/feeder_container.py +6 -5
- pypetkitapi/litter_container.py +6 -5
- pypetkitapi/water_fountain_container.py +5 -5
- {pypetkitapi-0.1.2.dist-info → pypetkitapi-0.2.1.dist-info}/METADATA +1 -1
- pypetkitapi-0.2.1.dist-info/RECORD +13 -0
- pypetkitapi-0.1.2.dist-info/RECORD +0 -13
- {pypetkitapi-0.1.2.dist-info → pypetkitapi-0.2.1.dist-info}/LICENSE +0 -0
- {pypetkitapi-0.1.2.dist-info → pypetkitapi-0.2.1.dist-info}/WHEEL +0 -0
pypetkitapi/client.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
"""Pypetkit Client: A Python library for interfacing with PetKit"""
|
2
2
|
|
3
|
+
import asyncio
|
3
4
|
from datetime import datetime, timedelta
|
4
5
|
from enum import StrEnum
|
5
6
|
import hashlib
|
@@ -17,6 +18,7 @@ from pypetkitapi.const import (
|
|
17
18
|
ERR_KEY,
|
18
19
|
LOGIN_DATA,
|
19
20
|
RES_KEY,
|
21
|
+
SUCCESS_KEY,
|
20
22
|
Header,
|
21
23
|
PetkitEndpoint,
|
22
24
|
PetkitURL,
|
@@ -44,7 +46,7 @@ class PetKitClient:
|
|
44
46
|
_session: SessionInfo | None = None
|
45
47
|
_servers_list: list[RegionInfo] = []
|
46
48
|
account_data: list[AccountData] = []
|
47
|
-
device_list:
|
49
|
+
device_list: dict[int, Feeder | Litter | WaterFountain] = {}
|
48
50
|
|
49
51
|
def __init__(
|
50
52
|
self,
|
@@ -136,6 +138,8 @@ class PetKitClient:
|
|
136
138
|
# Retrieve the list of servers
|
137
139
|
await self._get_base_url()
|
138
140
|
|
141
|
+
_LOGGER.debug("Logging in to PetKit server")
|
142
|
+
|
139
143
|
# Prepare the data to send
|
140
144
|
data = LOGIN_DATA.copy()
|
141
145
|
data["encrypt"] = "1"
|
@@ -210,6 +214,7 @@ class PetKitClient:
|
|
210
214
|
|
211
215
|
async def get_devices_data(self) -> None:
|
212
216
|
"""Get the devices data from the PetKit servers."""
|
217
|
+
start_time = datetime.now()
|
213
218
|
if not self.account_data:
|
214
219
|
await self._get_account_data()
|
215
220
|
|
@@ -219,19 +224,25 @@ class PetKitClient:
|
|
219
224
|
if account.device_list:
|
220
225
|
device_list.extend(account.device_list)
|
221
226
|
|
222
|
-
_LOGGER.
|
227
|
+
_LOGGER.debug("Fetch %s devices for this account", len(device_list))
|
228
|
+
|
229
|
+
tasks = []
|
223
230
|
for device in device_list:
|
224
231
|
_LOGGER.debug("Fetching devices data: %s", device)
|
225
232
|
device_type = device.device_type.lower()
|
226
|
-
# TODO: Fetch device records
|
227
233
|
if device_type in DEVICES_FEEDER:
|
228
|
-
|
234
|
+
tasks.append(self._fetch_device_data(device, Feeder))
|
229
235
|
elif device_type in DEVICES_LITTER_BOX:
|
230
|
-
|
236
|
+
tasks.append(self._fetch_device_data(device, Litter))
|
231
237
|
elif device_type in DEVICES_WATER_FOUNTAIN:
|
232
|
-
|
238
|
+
tasks.append(self._fetch_device_data(device, WaterFountain))
|
233
239
|
else:
|
234
240
|
_LOGGER.warning("Unknown device type: %s", device_type)
|
241
|
+
await asyncio.gather(*tasks)
|
242
|
+
|
243
|
+
end_time = datetime.now()
|
244
|
+
total_time = end_time - start_time
|
245
|
+
_LOGGER.debug("Petkit fetch took : %s", total_time)
|
235
246
|
|
236
247
|
async def _fetch_device_data(
|
237
248
|
self,
|
@@ -253,22 +264,28 @@ class PetKitClient:
|
|
253
264
|
)
|
254
265
|
device_data = data_class(**response)
|
255
266
|
device_data.device_type = device.device_type # Add the device_type attribute
|
256
|
-
_LOGGER.
|
257
|
-
|
267
|
+
_LOGGER.debug(
|
268
|
+
"Reading device type : %s (id=%s)", device.device_type, device.device_id
|
269
|
+
)
|
270
|
+
self.device_list[device.device_id] = device_data
|
258
271
|
|
259
272
|
async def send_api_request(
|
260
273
|
self,
|
261
|
-
|
274
|
+
device_id: int,
|
262
275
|
action: StrEnum,
|
263
276
|
setting: dict | None = None,
|
264
277
|
) -> None:
|
265
278
|
"""Control the device using the PetKit API."""
|
279
|
+
device = self.device_list.get(device_id)
|
280
|
+
if not device:
|
281
|
+
raise PypetkitError(f"Device with ID {device_id} not found.")
|
266
282
|
|
267
283
|
_LOGGER.debug(
|
268
|
-
"Control API
|
284
|
+
"Control API device=%s id=%s action=%s param=%s",
|
285
|
+
device.device_type,
|
286
|
+
device_id,
|
269
287
|
action,
|
270
288
|
setting,
|
271
|
-
device,
|
272
289
|
)
|
273
290
|
|
274
291
|
if device.device_type:
|
@@ -302,12 +319,16 @@ class PetKitClient:
|
|
302
319
|
params = action_info.params(device)
|
303
320
|
|
304
321
|
prep_req = PrepReq(base_url=self._base_url)
|
305
|
-
await prep_req.request(
|
322
|
+
res = await prep_req.request(
|
306
323
|
method=HTTPMethod.POST,
|
307
324
|
url=url,
|
308
325
|
data=params,
|
309
326
|
headers=headers,
|
310
327
|
)
|
328
|
+
if res == SUCCESS_KEY:
|
329
|
+
_LOGGER.info("Command executed successfully")
|
330
|
+
else:
|
331
|
+
_LOGGER.error("Command execution failed")
|
311
332
|
|
312
333
|
|
313
334
|
class PrepReq:
|
pypetkitapi/feeder_container.py
CHANGED
@@ -141,6 +141,7 @@ class StateFeeder(BaseModel):
|
|
141
141
|
door: int | None = None
|
142
142
|
feed_state: FeedState | None = Field(None, alias="feedState")
|
143
143
|
feeding: int | None = None
|
144
|
+
error_msg: str | None = Field(None, alias="errorMsg")
|
144
145
|
ota: int | None = None
|
145
146
|
overall: int | None = None
|
146
147
|
pim: int | None = None
|
@@ -163,10 +164,10 @@ class Feeder(BaseModel):
|
|
163
164
|
bt_mac: str | None = Field(None, alias="btMac")
|
164
165
|
cloud_product: CloudProduct | None = Field(None, alias="cloudProduct")
|
165
166
|
created_at: str | None = Field(None, alias="createdAt")
|
166
|
-
firmware:
|
167
|
-
firmware_details: list[FirmwareDetail]
|
168
|
-
hardware: int
|
169
|
-
id: int
|
167
|
+
firmware: float
|
168
|
+
firmware_details: list[FirmwareDetail] = Field(alias="firmwareDetails")
|
169
|
+
hardware: int
|
170
|
+
id: int
|
170
171
|
locale: str | None = None
|
171
172
|
mac: str | None = None
|
172
173
|
model_code: int | None = Field(None, alias="modelCode")
|
@@ -177,7 +178,7 @@ class Feeder(BaseModel):
|
|
177
178
|
settings: SettingsFeeder | None = None
|
178
179
|
share_open: int | None = Field(None, alias="shareOpen")
|
179
180
|
signup_at: str | None = Field(None, alias="signupAt")
|
180
|
-
sn: str
|
181
|
+
sn: str
|
181
182
|
state: StateFeeder | None = None
|
182
183
|
timezone: float | None = None
|
183
184
|
p2p_type: int | None = Field(None, alias="p2pType")
|
pypetkitapi/litter_container.py
CHANGED
@@ -91,6 +91,7 @@ class StateLitter(BaseModel):
|
|
91
91
|
box_full: bool | None = Field(None, alias="boxFull")
|
92
92
|
box_state: int | None = Field(None, alias="boxState")
|
93
93
|
deodorant_left_days: int | None = Field(None, alias="deodorantLeftDays")
|
94
|
+
error_msg: str | None = Field(None, alias="errorMsg")
|
94
95
|
frequent_restroom: int | None = Field(None, alias="frequentRestroom")
|
95
96
|
liquid_empty: bool | None = Field(None, alias="liquidEmpty")
|
96
97
|
liquid_lack: bool | None = Field(None, alias="liquidLack")
|
@@ -140,10 +141,10 @@ class Litter(BaseModel):
|
|
140
141
|
auto_upgrade: int | None = Field(None, alias="autoUpgrade")
|
141
142
|
bt_mac: str | None = Field(None, alias="btMac")
|
142
143
|
created_at: str | None = Field(None, alias="createdAt")
|
143
|
-
firmware:
|
144
|
-
firmware_details: list[FirmwareDetail]
|
145
|
-
hardware: int
|
146
|
-
id: int
|
144
|
+
firmware: float
|
145
|
+
firmware_details: list[FirmwareDetail] = Field(alias="firmwareDetails")
|
146
|
+
hardware: int
|
147
|
+
id: int
|
147
148
|
is_pet_out_tips: int | None = Field(None, alias="isPetOutTips")
|
148
149
|
locale: str | None = None
|
149
150
|
mac: str | None = None
|
@@ -156,7 +157,7 @@ class Litter(BaseModel):
|
|
156
157
|
settings: SettingsLitter | None = None
|
157
158
|
share_open: int | None = Field(None, alias="shareOpen")
|
158
159
|
signup_at: str | None = Field(None, alias="signupAt")
|
159
|
-
sn: str
|
160
|
+
sn: str
|
160
161
|
state: StateLitter | None = None
|
161
162
|
timezone: float | None = None
|
162
163
|
cloud_product: CloudProduct | None = Field(None, alias="cloudProduct") # For T5/T6
|
@@ -100,9 +100,9 @@ class WaterFountain(BaseModel):
|
|
100
100
|
filter_expected_days: int | None = Field(None, alias="filterExpectedDays")
|
101
101
|
filter_percent: int | None = Field(None, alias="filterPercent")
|
102
102
|
filter_warning: int | None = Field(None, alias="filterWarning")
|
103
|
-
firmware:
|
104
|
-
hardware: int
|
105
|
-
id: int
|
103
|
+
firmware: float
|
104
|
+
hardware: int
|
105
|
+
id: int
|
106
106
|
is_night_no_disturbing: int | None = Field(None, alias="isNightNoDisturbing")
|
107
107
|
lack_warning: int | None = Field(None, alias="lackWarning")
|
108
108
|
locale: str | None = None
|
@@ -110,14 +110,14 @@ class WaterFountain(BaseModel):
|
|
110
110
|
mac: str | None = None
|
111
111
|
mode: int | None = None
|
112
112
|
module_status: int | None = Field(None, alias="moduleStatus")
|
113
|
-
name: str
|
113
|
+
name: str
|
114
114
|
record_automatic_add_water: int | None = Field(
|
115
115
|
None, alias="recordAutomaticAddWater"
|
116
116
|
)
|
117
117
|
schedule: Schedule | None = None
|
118
118
|
secret: str | None = None
|
119
119
|
settings: SettingsFountain | None = None
|
120
|
-
sn: str
|
120
|
+
sn: str
|
121
121
|
status: Status | None = None
|
122
122
|
sync_time: str | None = Field(None, alias="syncTime")
|
123
123
|
timezone: float | None = None
|
@@ -0,0 +1,13 @@
|
|
1
|
+
pypetkitapi/__init__.py,sha256=eVpyGMD3tkYtiHUkdKEeNSZhQlZ4woI2Y5oVoV7CwXM,61
|
2
|
+
pypetkitapi/client.py,sha256=xfdhNAW3jsq9xQWgnEZTc2fAH7z4GHA3jtZlwDlmgCc,14635
|
3
|
+
pypetkitapi/command.py,sha256=ibJ0zenONy-FBvUvyIA_IvUnYEUezLpPxhC_9XZ6SwM,9282
|
4
|
+
pypetkitapi/const.py,sha256=49NMRaCGok20P-qfzlL6PH7QN9-QDuAsPh2Fejqf2iE,2945
|
5
|
+
pypetkitapi/containers.py,sha256=GQqZKaDgemQM4UDnugWYDP7N01anpJwO4VjQy2Gla3E,3109
|
6
|
+
pypetkitapi/exceptions.py,sha256=f9QY1EME9ha_vJJx4DuL_OBNpoynYVdtMFtVZbdfook,1129
|
7
|
+
pypetkitapi/feeder_container.py,sha256=IGXeAEbLkZhOTCzF2MhwqadIAKXg6jHbfU037dt6byY,10985
|
8
|
+
pypetkitapi/litter_container.py,sha256=aLAvcB8K_nx7iBRkAarZs-48HAj2NkG7XjJFonWMuME,8948
|
9
|
+
pypetkitapi/water_fountain_container.py,sha256=LcCTDjk7eSbnF7e38xev3D5mCv5wwJ6go8WGGBv-CaU,5278
|
10
|
+
pypetkitapi-0.2.1.dist-info/LICENSE,sha256=4FWnKolNLc1e3w6cVlT61YxfPh0DQNeQLN1CepKKSBg,1067
|
11
|
+
pypetkitapi-0.2.1.dist-info/METADATA,sha256=mb2SmQx9J0Vx-N5ukYHAlUodTLrU0M1TYc0psdIb57E,3700
|
12
|
+
pypetkitapi-0.2.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
13
|
+
pypetkitapi-0.2.1.dist-info/RECORD,,
|
@@ -1,13 +0,0 @@
|
|
1
|
-
pypetkitapi/__init__.py,sha256=eVpyGMD3tkYtiHUkdKEeNSZhQlZ4woI2Y5oVoV7CwXM,61
|
2
|
-
pypetkitapi/client.py,sha256=r_GJHi4gKuAnRAKwfro2G0xyq2aNRmaIfUTP6bWkdpE,13922
|
3
|
-
pypetkitapi/command.py,sha256=ibJ0zenONy-FBvUvyIA_IvUnYEUezLpPxhC_9XZ6SwM,9282
|
4
|
-
pypetkitapi/const.py,sha256=49NMRaCGok20P-qfzlL6PH7QN9-QDuAsPh2Fejqf2iE,2945
|
5
|
-
pypetkitapi/containers.py,sha256=GQqZKaDgemQM4UDnugWYDP7N01anpJwO4VjQy2Gla3E,3109
|
6
|
-
pypetkitapi/exceptions.py,sha256=f9QY1EME9ha_vJJx4DuL_OBNpoynYVdtMFtVZbdfook,1129
|
7
|
-
pypetkitapi/feeder_container.py,sha256=5dCgXAHafl2kMk4jM4JGPgE0f48JBs0UkA1TvLPTfXU,10994
|
8
|
-
pypetkitapi/litter_container.py,sha256=tKYd7iaj88TtR0W-wJ6U8PmsUzCcWg4ZisblOTKjKSg,8957
|
9
|
-
pypetkitapi/water_fountain_container.py,sha256=g_J1nYuNTlDg-ltvo2FZRTxKWLgW9E0GVzbFKO6jpA8,5346
|
10
|
-
pypetkitapi-0.1.2.dist-info/LICENSE,sha256=4FWnKolNLc1e3w6cVlT61YxfPh0DQNeQLN1CepKKSBg,1067
|
11
|
-
pypetkitapi-0.1.2.dist-info/METADATA,sha256=uBFcyKIvZ2s9OqUbW3NuGabVbzglHMPVQgSf3KbmFy4,3700
|
12
|
-
pypetkitapi-0.1.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
13
|
-
pypetkitapi-0.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|