petsafe-api 3.1.2__tar.gz → 3.3.0__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.
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/PKG-INFO +16 -2
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/README.md +15 -1
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/devices.py +43 -0
- petsafe_api-3.3.0/petsafe/local.py +556 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe_api.egg-info/PKG-INFO +16 -2
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe_api.egg-info/SOURCES.txt +1 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/setup.py +1 -1
- petsafe_api-3.3.0/tests/test_local.py +502 -0
- petsafe_api-3.3.0/tests/test_local_server.py +75 -0
- petsafe_api-3.1.2/petsafe/local.py +0 -118
- petsafe_api-3.1.2/tests/test_local.py +0 -168
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/LICENSE +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/__init__.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/__main__.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/client.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/const.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/general.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/pets.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/provisioning.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe/setup.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe_api.egg-info/dependency_links.txt +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe_api.egg-info/requires.txt +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/petsafe_api.egg-info/top_level.txt +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/setup.cfg +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/tests/test_provisioning.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/tests/test_setup.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/tests/test_smartdoor_modes.py +0 -0
- {petsafe_api-3.1.2 → petsafe_api-3.3.0}/tests/test_smartfeed_last_feeding.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: petsafe-api
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Provides ability to connect and control a PetSafe Smart Feed, Scoopfree, and Smart Door devices using the PetSafe API.
|
|
5
5
|
Home-page: https://github.com/ThomasHFWright/petsafe-api
|
|
6
6
|
Author: Jordan Stremming & Dominick Meglio & Thomas Wright
|
|
@@ -57,7 +57,7 @@ Thank you to both projects for building the API integrations for existing feeder
|
|
|
57
57
|
If installing from source code,
|
|
58
58
|
`python setup.py install`
|
|
59
59
|
|
|
60
|
-
## Local SmartDoor control and provisioning (3.
|
|
60
|
+
## Local SmartDoor control, management and provisioning (3.3.0)
|
|
61
61
|
|
|
62
62
|
`LocalPetSafeClient` connects to a compatible local server using its HTTPS origin
|
|
63
63
|
and API token. It does not use a PetSafe vendor login, and returns the same
|
|
@@ -77,6 +77,16 @@ async def main() -> None:
|
|
|
77
77
|
await door.unlock()
|
|
78
78
|
await door.smart_mode()
|
|
79
79
|
|
|
80
|
+
async for snapshot in client.iter_events():
|
|
81
|
+
print(snapshot["revision"], snapshot["door"])
|
|
82
|
+
|
|
83
|
+
pet = await client.create_pet({
|
|
84
|
+
"profile": {"name": "Example pet", "breed": []}, "timezone": "UTC"
|
|
85
|
+
})
|
|
86
|
+
async for scan in client.scan_rfid(door.api_name, "PETSAFE_KEY"):
|
|
87
|
+
if scan["state"] == "captured" and scan["restored"]:
|
|
88
|
+
await client.assign_rfid_scan(door.api_name, scan["id"], pet["petId"])
|
|
89
|
+
|
|
80
90
|
|
|
81
91
|
asyncio.run(main())
|
|
82
92
|
```
|
|
@@ -107,6 +117,10 @@ also requires supported BLE hardware or a nearby proxy and an HTTPS hostname and
|
|
|
107
117
|
certificate trusted by the SmartDoor; hardware testing used an Amazon-trusted
|
|
108
118
|
certificate. A raw IP address is not a supported or promised substitute.
|
|
109
119
|
|
|
120
|
+
Local maintenance helpers include allowlisted native command submission and firmware
|
|
121
|
+
inspection, staging, installation, and cancellation. `install_firmware()` is an explicit
|
|
122
|
+
physical-device mutation; returned job state is not a promise of firmware outcome.
|
|
123
|
+
|
|
110
124
|
## Cloud login tokens
|
|
111
125
|
You **must** use tokens to interact with the PetSafe Smart-Feed API.
|
|
112
126
|
There are two methods to retrieve tokens:
|
|
@@ -24,7 +24,7 @@ Thank you to both projects for building the API integrations for existing feeder
|
|
|
24
24
|
If installing from source code,
|
|
25
25
|
`python setup.py install`
|
|
26
26
|
|
|
27
|
-
## Local SmartDoor control and provisioning (3.
|
|
27
|
+
## Local SmartDoor control, management and provisioning (3.3.0)
|
|
28
28
|
|
|
29
29
|
`LocalPetSafeClient` connects to a compatible local server using its HTTPS origin
|
|
30
30
|
and API token. It does not use a PetSafe vendor login, and returns the same
|
|
@@ -44,6 +44,16 @@ async def main() -> None:
|
|
|
44
44
|
await door.unlock()
|
|
45
45
|
await door.smart_mode()
|
|
46
46
|
|
|
47
|
+
async for snapshot in client.iter_events():
|
|
48
|
+
print(snapshot["revision"], snapshot["door"])
|
|
49
|
+
|
|
50
|
+
pet = await client.create_pet({
|
|
51
|
+
"profile": {"name": "Example pet", "breed": []}, "timezone": "UTC"
|
|
52
|
+
})
|
|
53
|
+
async for scan in client.scan_rfid(door.api_name, "PETSAFE_KEY"):
|
|
54
|
+
if scan["state"] == "captured" and scan["restored"]:
|
|
55
|
+
await client.assign_rfid_scan(door.api_name, scan["id"], pet["petId"])
|
|
56
|
+
|
|
47
57
|
|
|
48
58
|
asyncio.run(main())
|
|
49
59
|
```
|
|
@@ -74,6 +84,10 @@ also requires supported BLE hardware or a nearby proxy and an HTTPS hostname and
|
|
|
74
84
|
certificate trusted by the SmartDoor; hardware testing used an Amazon-trusted
|
|
75
85
|
certificate. A raw IP address is not a supported or promised substitute.
|
|
76
86
|
|
|
87
|
+
Local maintenance helpers include allowlisted native command submission and firmware
|
|
88
|
+
inspection, staging, installation, and cancellation. `install_firmware()` is an explicit
|
|
89
|
+
physical-device mutation; returned job state is not a promise of firmware outcome.
|
|
90
|
+
|
|
77
91
|
## Cloud login tokens
|
|
78
92
|
You **must** use tokens to interact with the PetSafe Smart-Feed API.
|
|
79
93
|
There are two methods to retrieve tokens:
|
|
@@ -705,6 +705,21 @@ class DeviceSmartDoor:
|
|
|
705
705
|
self.data["schedules"] = schedules
|
|
706
706
|
return schedules
|
|
707
707
|
|
|
708
|
+
async def get_schedule(self, schedule_id: str) -> dict:
|
|
709
|
+
"""Return one SmartDoor schedule by identifier."""
|
|
710
|
+
|
|
711
|
+
if not schedule_id:
|
|
712
|
+
raise ValueError("schedule_id must be provided")
|
|
713
|
+
response = await self.client.api_get(
|
|
714
|
+
f"smartdoor/product/schedules/{self.api_name}/{schedule_id}"
|
|
715
|
+
)
|
|
716
|
+
response.raise_for_status()
|
|
717
|
+
payload = json.loads(response.content.decode("UTF-8"))
|
|
718
|
+
data = payload.get("data", payload)
|
|
719
|
+
if not isinstance(data, dict):
|
|
720
|
+
raise ValueError("Unexpected response payload for SmartDoor schedule")
|
|
721
|
+
return data
|
|
722
|
+
|
|
708
723
|
async def get_override_schedules(self) -> list[dict]:
|
|
709
724
|
"""Return override schedules configured for the SmartDoor."""
|
|
710
725
|
|
|
@@ -736,6 +751,15 @@ class DeviceSmartDoor:
|
|
|
736
751
|
await self.update_data()
|
|
737
752
|
return data
|
|
738
753
|
|
|
754
|
+
async def clear_override_schedule(self, *, update_data: bool = True) -> None:
|
|
755
|
+
"""Clear the SmartDoor's temporary access override."""
|
|
756
|
+
|
|
757
|
+
await self.client.api_delete(
|
|
758
|
+
f"smartdoor/product/override/schedules/{self.api_name}"
|
|
759
|
+
)
|
|
760
|
+
if update_data:
|
|
761
|
+
await self.update_data()
|
|
762
|
+
|
|
739
763
|
async def save_schedule(
|
|
740
764
|
self, schedule: dict, *, update_data: bool = True
|
|
741
765
|
) -> dict:
|
|
@@ -755,6 +779,25 @@ class DeviceSmartDoor:
|
|
|
755
779
|
await self.update_data()
|
|
756
780
|
return data
|
|
757
781
|
|
|
782
|
+
async def update_schedule(
|
|
783
|
+
self, schedule: dict, *, update_data: bool = True
|
|
784
|
+
) -> dict:
|
|
785
|
+
"""Update an existing SmartDoor schedule."""
|
|
786
|
+
|
|
787
|
+
if not isinstance(schedule, dict) or not schedule.get("scheduleId"):
|
|
788
|
+
raise ValueError("schedule with scheduleId must be provided")
|
|
789
|
+
payload = dict(schedule)
|
|
790
|
+
payload.setdefault("thingName", self.api_name)
|
|
791
|
+
response = await self.client.api_put(
|
|
792
|
+
"smartdoor/product/schedules", data=payload
|
|
793
|
+
)
|
|
794
|
+
response.raise_for_status()
|
|
795
|
+
response_payload = json.loads(response.content.decode("UTF-8"))
|
|
796
|
+
data = response_payload.get("data", response_payload)
|
|
797
|
+
if update_data:
|
|
798
|
+
await self.update_data()
|
|
799
|
+
return data
|
|
800
|
+
|
|
758
801
|
async def delete_schedule(
|
|
759
802
|
self, schedule_id: str, *, update_data: bool = True
|
|
760
803
|
) -> None:
|