From bfcfe407eaa3b4c370ff97f9574681cb911127f2 Mon Sep 17 00:00:00 2001 From: Joostlek Date: Mon, 24 Nov 2025 17:48:05 +0100 Subject: [PATCH] Add method to get installed app --- src/pysmartthings/__init__.py | 2 ++ src/pysmartthings/models.py | 12 +++++++++++ src/pysmartthings/smartthings.py | 19 ++++++++++++++++ tests/__snapshots__/test_smartapp.ambr | 9 ++++++++ tests/test_smartapp.py | 30 +++++++++++++++++++++++++- 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/__snapshots__/test_smartapp.ambr diff --git a/src/pysmartthings/__init__.py b/src/pysmartthings/__init__.py index 41ff4e7..e4eb8d6 100644 --- a/src/pysmartthings/__init__.py +++ b/src/pysmartthings/__init__.py @@ -30,6 +30,7 @@ DeviceType, ErrorDetails, ErrorResponse, + InstalledApp, Lifecycle, Location, LocationResponse, @@ -64,6 +65,7 @@ "DeviceType", "ErrorDetails", "ErrorResponse", + "InstalledApp", "Lifecycle", "Location", "LocationResponse", diff --git a/src/pysmartthings/models.py b/src/pysmartthings/models.py index d285f60..f74da9c 100644 --- a/src/pysmartthings/models.py +++ b/src/pysmartthings/models.py @@ -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.""" diff --git a/src/pysmartthings/smartthings.py b/src/pysmartthings/smartthings.py index 0243b4c..7f43d65 100644 --- a/src/pysmartthings/smartthings.py +++ b/src/pysmartthings/smartthings.py @@ -33,6 +33,7 @@ DeviceStatus, ErrorResponse, EventType, + InstalledApp, Lifecycle, Location, LocationResponse, @@ -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, diff --git a/tests/__snapshots__/test_smartapp.ambr b/tests/__snapshots__/test_smartapp.ambr new file mode 100644 index 0000000..3c334b4 --- /dev/null +++ b/tests/__snapshots__/test_smartapp.ambr @@ -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', + }) +# --- diff --git a/tests/test_smartapp.py b/tests/test_smartapp.py index dde89af..9bdc0b6 100644 --- a/tests/test_smartapp.py +++ b/tests/test_smartapp.py @@ -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 @@ -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, + )