Skip to content
This repository was archived by the owner on Jun 28, 2024. It is now read-only.

Commit 816b7ed

Browse files
committed
version 0.2.2, add access_code support
1 parent 5921211 commit 816b7ed

File tree

6 files changed

+143
-1
lines changed

6 files changed

+143
-1
lines changed

examples/interactive_set_access_codes/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
This program resets a sandbox, creates a webview, asks a user to login to
3+
that webview, retrieves the locks they own, then sets a code on the front door.
4+
"""
5+
from seamapi import Seam
6+
from dotenv import load_dotenv
7+
from examples.utils import bcolors, yes_strings
8+
from pprint import pprint
9+
import sys
10+
11+
load_dotenv()
12+
13+
if input("This will reset your workspace sandbox, continue? (Y/n) ") not in yes_strings:
14+
raise Exception("Stopped by user")
15+
16+
seam = Seam()
17+
18+
print("Reseting sandbox...")
19+
seam.workspaces.reset_sandbox()
20+
21+
print("Creating a Connect Webview...")
22+
webview = seam.connect_webviews.create(accepted_providers=["august"])
23+
24+
print("This is my webview:")
25+
pprint(webview)
26+
27+
print(
28+
bcolors.OKCYAN
29+
+ f"\nGo to the URL below and login\n\n{webview.url}\n\n\t[email protected]\n\t1234\n\n"
30+
+ bcolors.ENDC
31+
)
32+
33+
input("Press enter when you're done:")
34+
35+
updated_webview = seam.connect_webviews.get(webview.connect_webview_id)
36+
37+
print("This is my updated webview:")
38+
pprint(updated_webview)
39+
40+
if updated_webview.login_successful:
41+
print(bcolors.OKGREEN + "Successfully logged in!" + bcolors.ENDC)
42+
else:
43+
print(
44+
bcolors.FAIL
45+
+ "\nWebview wasn't logged in, did you forget to log in?\n"
46+
+ bcolors.ENDC
47+
)
48+
sys.exit(1)
49+
50+
51+
print("Listing all the connected locks for our new account:")
52+
locks = seam.locks.list()
53+
pprint(locks)
54+
55+
# We can probably replace this with seam.locks.get and a filter
56+
front_door = next(
57+
lock
58+
for lock in locks
59+
if lock.properties["august_metadata"]["lock_name"] == "FRONT DOOR"
60+
)
61+
62+
print("Setting the code 123459 on FRONT DOOR")
63+
seam.access_codes.create(
64+
device=front_door, name="My Personal Entry Code", code="123459"
65+
)
66+
67+
all_access_codes_on_front_door = seam.access_codes.list(device=front_door)
68+
pprint(all_access_codes_on_front_door)

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "seamapi"
3-
version = "0.1.2"
3+
version = "0.2.2"
44
description = "A Python Library for Seam's API https://getseam.com"
55
authors = ["Severin Ibarluzea <[email protected]>"]
66
license = "MIT"

seamapi/access_codes.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from seamapi.types import (
2+
AbstractAccessCodes,
3+
AccessCode,
4+
Device,
5+
DeviceId,
6+
ActionAttempt,
7+
AbstractSeam as Seam,
8+
)
9+
from typing import List, Union
10+
import requests
11+
12+
13+
def to_device_id(device: Union[DeviceId, Device]) -> str:
14+
if isinstance(device, str):
15+
return device
16+
return device.device_id
17+
18+
19+
class AccessCodes(AbstractAccessCodes):
20+
seam: Seam
21+
22+
def __init__(self, seam: Seam):
23+
self.seam = seam
24+
25+
def list(self, device: Union[DeviceId, Device]) -> List[AccessCode]:
26+
device_id = to_device_id(device)
27+
res = requests.get(
28+
f"{self.seam.api_url}/access_codes/list?device_id={device_id}",
29+
headers={"Authorization": f"Bearer {self.seam.api_key}"},
30+
)
31+
if not res.ok:
32+
raise Exception(res.text)
33+
access_codes = res.json()["access_codes"]
34+
return [AccessCode.from_dict(ac) for ac in access_codes]
35+
36+
def create(
37+
self, device: Union[DeviceId, Device], name: str, code: str
38+
) -> ActionAttempt:
39+
device_id = to_device_id(device)
40+
res = requests.post(
41+
f"{self.seam.api_url}/access_codes/create",
42+
headers={"Authorization": f"Bearer {self.seam.api_key}"},
43+
json={
44+
"device_id": device_id,
45+
"name": name,
46+
"code": code,
47+
},
48+
)
49+
if not res.ok:
50+
raise Exception(res.text)
51+
return ActionAttempt(action_attempt_id="", status="pending")

seamapi/seam.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .devices import Devices
55
from .connect_webviews import ConnectWebviews
66
from .locks import Locks
7+
from .access_codes import AccessCodes
78
from .types import AbstractSeam
89

910

@@ -24,3 +25,4 @@ def __init__(self, api_key: Optional[str] = None):
2425
self.connect_webviews = ConnectWebviews(seam=self)
2526
self.devices = Devices(seam=self)
2627
self.locks = Locks(seam=self)
28+
self.access_codes = AccessCodes(seam=self)

seamapi/types.py

+21
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ class ConnectWebview:
4343
third_party_account_id: Optional[str]
4444

4545

46+
@dataclass_json
47+
@dataclass
48+
class AccessCode:
49+
access_code_id: str
50+
type: str
51+
code: str
52+
53+
4654
class AbstractLocks(abc.ABC):
4755
@abc.abstractmethod
4856
def list(self) -> List[Device]:
@@ -61,6 +69,18 @@ def unlock_door(self, device: Union[DeviceId, Device]) -> ActionAttempt:
6169
raise NotImplementedError
6270

6371

72+
class AbstractAccessCodes(abc.ABC):
73+
@abc.abstractmethod
74+
def list(self, device: Union[DeviceId, Device]) -> List[AccessCode]:
75+
raise NotImplementedError
76+
77+
@abc.abstractmethod
78+
def create(
79+
self, device: Union[DeviceId, Device], name: str, code: str
80+
) -> ActionAttempt:
81+
raise NotImplementedError
82+
83+
6484
class AbstractActionAttempt(abc.ABC):
6585
@abc.abstractmethod
6686
def list(self) -> List[ActionAttempt]:
@@ -122,6 +142,7 @@ class AbstractSeam(abc.ABC):
122142
connect_webviews: AbstractConnectWebviews
123143
locks: AbstractLocks
124144
devices: AbstractDevices
145+
access_codes: AbstractAccessCodes
125146

126147
@abc.abstractmethod
127148
def __init__(self, api_key: Optional[str] = None):

0 commit comments

Comments
 (0)