petsafe-api 3.0.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.
petsafe/general.py ADDED
@@ -0,0 +1,29 @@
1
+ """Helpers for miscellaneous PetSafe platform endpoints."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import TYPE_CHECKING, Any, Dict, List
7
+
8
+ if TYPE_CHECKING: # pragma: no cover - for type checking only
9
+ from .client import PetSafeClient
10
+
11
+
12
+ async def list_product_sharing(client: "PetSafeClient") -> List[Dict[str, Any]]:
13
+ """Return product sharing relationships for the authenticated account."""
14
+
15
+ response = await client.api_get("directory/product-sharing")
16
+ payload = json.loads(response.content.decode("UTF-8"))
17
+ data = payload.get("data", payload)
18
+ return data if isinstance(data, list) else [data]
19
+
20
+
21
+ async def get_account_details(client: "PetSafeClient") -> Dict[str, Any]:
22
+ """Return the account details for the authenticated PetSafe user."""
23
+
24
+ response = await client.api_get("directory/account")
25
+ payload = json.loads(response.content.decode("UTF-8"))
26
+ data = payload.get("data", payload)
27
+ if isinstance(data, dict):
28
+ return data
29
+ raise ValueError("Unexpected response payload for account details")
petsafe/pets.py ADDED
@@ -0,0 +1,35 @@
1
+ """Convenience helpers for PetSafe pet-related API endpoints."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import TYPE_CHECKING, Any, Dict, List
7
+
8
+ if TYPE_CHECKING: # pragma: no cover - for type checking only
9
+ from .client import PetSafeClient
10
+
11
+
12
+ async def list_pets(client: "PetSafeClient") -> List[Dict[str, Any]]:
13
+ """Return all pets configured in the account."""
14
+
15
+ response = await client.api_get("pets/pets")
16
+ payload = json.loads(response.content.decode("UTF-8"))
17
+ data = payload.get("data", payload)
18
+ return data if isinstance(data, list) else [data]
19
+
20
+
21
+ async def list_pet_products(
22
+ client: "PetSafeClient", pet_id: str
23
+ ) -> List[Dict[str, Any]]:
24
+ """Return all products associated with the provided pet identifier."""
25
+
26
+ if not pet_id:
27
+ raise ValueError("pet_id must be provided")
28
+
29
+ from urllib.parse import quote_plus
30
+
31
+ path = f"directory/petProduct?petId={quote_plus(pet_id)}"
32
+ response = await client.api_get(path)
33
+ payload = json.loads(response.content.decode("UTF-8"))
34
+ data = payload.get("data", payload)
35
+ return data if isinstance(data, list) else [data]
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: petsafe-api
3
+ Version: 3.0.1
4
+ Summary: Provides ability to connect and control a PetSafe Smart Feed, Scoopfree, and Smart Door devices using the PetSafe API.
5
+ Home-page: https://github.com/ThomasHFWright/petsafe-api
6
+ Author: Jordan Stremming & Dominick Meglio & Thomas Wright
7
+ Author-email: thomas.h.f.wright@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: httpx
16
+ Requires-Dist: botocore
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: license
24
+ Dynamic: license-file
25
+ Dynamic: requires-dist
26
+ Dynamic: requires-python
27
+ Dynamic: summary
28
+
29
+ # petsafe-api
30
+ Connect and control PetSafe Smart Feed, ScoopFree, and Smart Door devices using the PetSafe API.
31
+
32
+ > **BREAKING CHANGE:** Version 2.0 uses the new PetSafe API.
33
+ > You will need to request new tokens.
34
+
35
+ > PetSafe will lock your account if you request data more often than once per 5 minutes.
36
+
37
+ ## Project rename
38
+ This repository is now named **petsafe-api** and the published package name is **petsafe-api** on PyPI.
39
+
40
+ > Import paths are unchanged: continue using `import petsafe` and `python -m petsafe`.
41
+
42
+ ## Acknowledgements
43
+ This project builds on the excellent prior work from the original developers:
44
+ - https://github.com/Techzune/petsafe_smartfeed
45
+ - https://github.com/dcmeglio/petsafe
46
+
47
+ Thank you to both projects for building the API integrations for existing feeder and ScoopFree functionality. This repository includes all of that previous work, with Smart Door API support added on top.
48
+
49
+ ## Installation
50
+ `pip install petsafe-api`
51
+
52
+ If installing from source code,
53
+ `python setup.py install`
54
+
55
+ ## Login tokens
56
+ You **must** use tokens to interact with the PetSafe Smart-Feed API.
57
+ There are two methods to retrieve tokens:
58
+
59
+ #### Get tokens using command line
60
+ 1. Execute `python -m petsafe [email_address]` to request an email code.
61
+ 2. Check your email for an email code from PetSafe.
62
+ 3. Enter your code to generate tokens.
63
+
64
+ #### Get tokens using Python
65
+ ```python
66
+ import petsafe as sf
67
+
68
+
69
+ # replace with your email address
70
+ client = sf.PetSafeClient(email="email@example.com")
71
+ client.request_code()
72
+
73
+ # check your email for a code
74
+ code = input("Enter email code: ")
75
+ token = client.request_tokens_from_code(code)
76
+
77
+ print("email:", client.email)
78
+ print("id_token:", client.id_token)
79
+ print("refresh_token:", client.refresh_token)
80
+ print("access_token:", client.access_token)
81
+ ```
82
+
83
+
84
+ ## Example usage
85
+ #### List feeders
86
+
87
+ ```python
88
+ import petsafe as sf
89
+
90
+ client = sf.PetSafeClient(email="email@example.com",
91
+ id_token="YOUR_ID_TOKEN",
92
+ refresh_token="YOUR_REFRESH_TOKEN",
93
+ access_token="YOUR_ACCESS_TOKEN")
94
+ devices = sf.devices.get_feeders(client)
95
+
96
+ # print all feeders
97
+ for device in devices:
98
+ print(device)
99
+
100
+ ```
101
+ #### Feed 1/8 cup at normal speed
102
+ ```python
103
+ import petsafe as sf
104
+
105
+ client = sf.PetSafeClient(email="email@example.com",
106
+ id_token="YOUR_ID_TOKEN",
107
+ refresh_token="YOUR_REFRESH_TOKEN",
108
+ access_token="YOUR_ACCESS_TOKEN")
109
+ devices = sf.devices.get_feeders(client)
110
+
111
+ # get the first feeder
112
+ feeder = devices[0]
113
+ feeder.feed(amount=1, slow_feed=False)
114
+
115
+ ```
116
+ #### Get current battery level (0 - 100)
117
+ ```python
118
+ import petsafe as sf
119
+
120
+ client = sf.PetSafeClient(email="email@example.com",
121
+ id_token="YOUR_ID_TOKEN",
122
+ refresh_token="YOUR_REFRESH_TOKEN",
123
+ access_token="YOUR_ACCESS_TOKEN")
124
+ devices = sf.devices.get_feeders(client)
125
+
126
+ # get the first feeder
127
+ feeder = devices[0]
128
+ print(feeder.battery_level)
129
+
130
+ ```
131
+ #### Get current food level
132
+ ```python
133
+ import petsafe as sf
134
+
135
+ client = sf.PetSafeClient(email="email@example.com",
136
+ id_token="YOUR_ID_TOKEN",
137
+ refresh_token="YOUR_REFRESH_TOKEN",
138
+ access_token="YOUR_ACCESS_TOKEN")
139
+ devices = sf.devices.get_feeders(client)
140
+
141
+ # get the first feeder
142
+ feeder = devices[0]
143
+ status = feeder.food_low_status
144
+
145
+ if status == 0:
146
+ print("Feeder has food.")
147
+ elif status == 1:
148
+ print("Feeder is low on food.")
149
+ elif status == 2:
150
+ print("Feeder is out of food.")
151
+
152
+ ```
153
+
154
+ ## SmartDoor controls
155
+ ```python
156
+ import asyncio
157
+
158
+ import petsafe as sf
159
+
160
+
161
+ async def main() -> None:
162
+ client = sf.PetSafeClient(
163
+ email="email@example.com",
164
+ id_token="YOUR_ID_TOKEN",
165
+ refresh_token="YOUR_REFRESH_TOKEN",
166
+ access_token="YOUR_ACCESS_TOKEN",
167
+ )
168
+
169
+ doors = await client.get_smartdoors()
170
+ door = doors[0]
171
+
172
+ # Manually lock the door and refresh its reported state
173
+ await door.lock()
174
+
175
+ # Switch back to Smart mode without forcing a refresh
176
+ await door.smart_mode(update_data=False)
177
+
178
+ # Or use the client helpers that return the updated door instance
179
+ updated = await client.manual_unlock_smartdoor(door.api_name)
180
+ print(updated.mode)
181
+
182
+
183
+ asyncio.run(main())
184
+ ```
185
+
186
+ # get litterboxes
187
+ ```python
188
+ import petsafe as sf
189
+
190
+ client = sf.PetSafeClient(email="email@example.com",
191
+ id_token="YOUR_ID_TOKEN",
192
+ refresh_token="YOUR_REFRESH_TOKEN",
193
+ access_token="YOUR_ACCESS_TOKEN")
194
+ devices = sf.devices.get_litterboxes(client)
195
+
196
+ # print all litterboxes
197
+ for device in devices:
198
+ print(device)
199
+
200
+ ```
201
+
202
+ # get litterbox activity
203
+ ```python
204
+ import petsafe as sf
205
+
206
+ client = sf.PetSafeClient(email="email@example.com",
207
+ id_token="YOUR_ID_TOKEN",
208
+ refresh_token="YOUR_REFRESH_TOKEN",
209
+ access_token="YOUR_ACCESS_TOKEN")
210
+ devices = sf.devices.get_litterboxes(client)
211
+
212
+ litterbox = devices[0]
213
+ print(litterbox.get_schedule())
214
+
215
+ ```
216
+
217
+ # rake the litterbox
218
+ ```python
219
+ import petsafe as sf
220
+
221
+ client = sf.PetSafeClient(email="email@example.com",
222
+ id_token="YOUR_ID_TOKEN",
223
+ refresh_token="YOUR_REFRESH_TOKEN",
224
+ access_token="YOUR_ACCESS_TOKEN")
225
+ devices = sf.devices.get_litterboxes(client)
226
+
227
+ litterbox = devices[0]
228
+ litterbox.rake()
229
+
230
+ ```
231
+
232
+ # modify the litterbox rake timer
233
+ ```python
234
+ import petsafe as sf
235
+
236
+ client = sf.PetSafeClient(email="email@example.com",
237
+ id_token="YOUR_ID_TOKEN",
238
+ refresh_token="YOUR_REFRESH_TOKEN",
239
+ access_token="YOUR_ACCESS_TOKEN")
240
+ devices = sf.devices.get_litterboxes(client)
241
+
242
+ litterbox = devices[0]
243
+ litterbox.modify_timer(15)
244
+
245
+ ```
246
+
247
+ # reset the litterbox rake count
248
+ ```python
249
+ import petsafe as sf
250
+
251
+ client = sf.PetSafeClient(email="email@example.com",
252
+ id_token="YOUR_ID_TOKEN",
253
+ refresh_token="YOUR_REFRESH_TOKEN",
254
+ access_token="YOUR_ACCESS_TOKEN")
255
+ devices = sf.devices.get_litterboxes(client)
256
+
257
+ litterbox = devices[0]
258
+ litterbox.reset()
259
+
260
+ ```
261
+
262
+ ## Contributing
263
+ All contributions are welcome.
264
+ Please, feel free to create a pull request!
@@ -0,0 +1,12 @@
1
+ petsafe/__init__.py,sha256=gAqJipbqEVw490qLBunZjB7rhYArvykjxnr-6l2SNKs,71
2
+ petsafe/__main__.py,sha256=Reh0jBps179FX5eFiRiZGHuvWR2KL583DATe_KhUL0I,762
3
+ petsafe/client.py,sha256=xpVo6xRYsR9rIfWlrqiHk8k4GfdjRwf3ESZcuh4ey7s,11972
4
+ petsafe/const.py,sha256=OXxo-GfU_VJJY8ldy15jgyatplyLq-to-Wmfx5EpIgQ,405
5
+ petsafe/devices.py,sha256=YvM8b6jwrpEfwaMeBBboyIgQTDiB1TyDag6BEHUFrFY,29331
6
+ petsafe/general.py,sha256=LIARBEiO8jnNLN_5bC6T1x5GrUHTLnTZNnNDayPCl_o,1070
7
+ petsafe/pets.py,sha256=4ZyC0a15lf0Jy_O67Mq9RQZJynG_U4jipc8PLsCs8a8,1139
8
+ petsafe_api-3.0.1.dist-info/licenses/LICENSE,sha256=3R2pheY3uCSdeAzg6Lr8KiAuqKwxo4UzGD2j-15G5w4,1059
9
+ petsafe_api-3.0.1.dist-info/METADATA,sha256=H1aV5X7YQNjvYLrvAy2RItAmtqNTNjFWy7IhoS5mtnI,7132
10
+ petsafe_api-3.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
11
+ petsafe_api-3.0.1.dist-info/top_level.txt,sha256=5D0ZgkQJjlXEEVOeHs3F3TGlSXJO_bR1TaoSuKkggZA,8
12
+ petsafe_api-3.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2020 Jordan Stremming
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ petsafe