Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/pysmartthings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
DeviceType,
ErrorDetails,
ErrorResponse,
InstalledApp,
Lifecycle,
Location,
LocationResponse,
Expand Down Expand Up @@ -64,6 +65,7 @@
"DeviceType",
"ErrorDetails",
"ErrorResponse",
"InstalledApp",
"Lifecycle",
"Location",
"LocationResponse",
Expand Down
12 changes: 12 additions & 0 deletions src/pysmartthings/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
ALREADY_LOGGED_CAPABILITIES = set()


@dataclass
class InstalledApp(DataClassORJSONMixin):
"""Installed app model."""

installed_app_id: str = field(metadata=field_options(alias="installedAppId"))
location_id: str = field(metadata=field_options(alias="locationId"))
app_id: str = field(metadata=field_options(alias="appId"))
display_name: str | None = field(
metadata=field_options(alias="displayName"), default=None
)


@dataclass
class BaseLocation(DataClassORJSONMixin):
"""Base location model."""
Expand Down
19 changes: 19 additions & 0 deletions src/pysmartthings/smartthings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
DeviceStatus,
ErrorResponse,
EventType,
InstalledApp,
Lifecycle,
Location,
LocationResponse,
Expand Down Expand Up @@ -353,6 +354,24 @@ async def delete_smart_app(

await self.__internal_request(METH_DELETE, url, headers)

async def get_installed_app(
self, personal_access_token: str, installed_app_id: str
) -> InstalledApp:
"""Delete a SmartApp."""
url = URL.build(
scheme="https",
host=API_BASE,
port=443,
).joinpath(f"v1/installedapps/{installed_app_id}")

headers = {
"Accept": f"application/vnd.smartthings+json;v={API_VERSION}",
"Authorization": f"Bearer {personal_access_token}",
}

resp = await self.__internal_request(METH_GET, url, headers)
return InstalledApp.from_json(resp)

async def execute_device_command(
self,
device_id: str,
Expand Down
9 changes: 9 additions & 0 deletions tests/__snapshots__/test_smartapp.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# serializer version: 1
# name: test_get_installed_app
dict({
'app_id': 'c6cde2b0-203e-44cf-a510-3b3ed4706996',
'display_name': 'pysmartthings',
'installed_app_id': '4514eb36-f5fd-4ab2-9520-0597acd1d212',
'location_id': '397678e5-9995-4a39-9d9f-ae6ba310236b',
})
# ---
30 changes: 29 additions & 1 deletion tests/test_smartapp.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Tests for SmartThings SmartApp endpoints."""

from aiohttp.hdrs import METH_DELETE
from aiohttp.hdrs import METH_DELETE, METH_GET
from aioresponses import aioresponses
from syrupy import SnapshotAssertion

from pysmartthings import SmartThings
from . import load_fixture

from .const import MOCK_URL, HEADERS

Expand All @@ -26,3 +28,29 @@ async def test_deleting_smart_app(
params=None,
json=None,
)


async def test_get_installed_app(
client: SmartThings,
responses: aioresponses,
snapshot: SnapshotAssertion,
) -> None:
"""Test getting an installed SmartApp."""
responses.get(
f"{MOCK_URL}/v1/installedapps/4514eb36-f5fd-4ab2-9520-0597acd1d212",
status=200,
body=load_fixture("installedapp_get_response.json"),
)
assert (
await client.get_installed_app(
"abcabcabcabc", "4514eb36-f5fd-4ab2-9520-0597acd1d212"
)
== snapshot
)
responses.assert_called_once_with(
f"{MOCK_URL}/v1/installedapps/4514eb36-f5fd-4ab2-9520-0597acd1d212",
METH_GET,
headers={**HEADERS, "Authorization": "Bearer abcabcabcabc"},
params=None,
json=None,
)
Loading