place-integration-api 0.2.4__tar.gz → 0.2.6__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.
- {place_integration_api-0.2.4/src/place_integration_api.egg-info → place_integration_api-0.2.6}/PKG-INFO +16 -2
- place_integration_api-0.2.6/README.md +15 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/pyproject.toml +4 -2
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/auth/abstract_auth.py +3 -1
- place_integration_api-0.2.6/src/place/errors.py +9 -0
- place_integration_api-0.2.6/src/place/provider.py +43 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6/src/place_integration_api.egg-info}/PKG-INFO +16 -2
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place_integration_api.egg-info/SOURCES.txt +1 -0
- place_integration_api-0.2.6/tests/test_auth.py +70 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/tests/test_provider.py +79 -0
- place_integration_api-0.2.4/README.md +0 -3
- place_integration_api-0.2.4/src/place/provider.py +0 -38
- place_integration_api-0.2.4/tests/test_auth.py +0 -31
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/LICENSE +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/setup.cfg +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/auth/__init__.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/auth/aws_srp.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/auth/srp_auth.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/auth/tokens.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/config.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/messages.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/__init__.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/credentials.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/device_shadow.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/discover_device.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/models.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/mqtt_message.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/mqtt_client.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place_integration_api.egg-info/dependency_links.txt +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place_integration_api.egg-info/requires.txt +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place_integration_api.egg-info/top_level.txt +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/tests/test_models.py +0 -0
- {place_integration_api-0.2.4 → place_integration_api-0.2.6}/tests/test_mqtt_client.py +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: place-integration-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Python APIs for Cognito-authenticated MQTT flows and Home Assistant discovery for Gentex Place.
|
|
5
5
|
Author-email: Nicholas Aelick <niaexa@syntronic.com>, Andrew Tran <andrew.tran@gentex.com>
|
|
6
|
-
Project-URL: Homepage, https://
|
|
6
|
+
Project-URL: Homepage, https://placehomesolutions.com
|
|
7
|
+
Project-URL: Issues, https://placehomesolutions.com/support
|
|
8
|
+
Project-URL: Repository, https://github.com/Gentex-Corporation/place-integration-api
|
|
7
9
|
Classifier: Programming Language :: Python :: 3
|
|
8
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
9
11
|
Classifier: Operating System :: OS Independent
|
|
@@ -25,3 +27,15 @@ Dynamic: license-file
|
|
|
25
27
|
# Place integration API
|
|
26
28
|
|
|
27
29
|
This project contains a python API to connect MQTT data from Place devices to Place's Home Assistant integration
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
This repo utilizes VS Code [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) so you don't need to alter your global python environment.
|
|
34
|
+
|
|
35
|
+
## Installing dependencies
|
|
36
|
+
|
|
37
|
+
Use `pip` to install required dependencies by running `pip install -r requirements.txt` from the project root.
|
|
38
|
+
|
|
39
|
+
## Updating dependencies
|
|
40
|
+
|
|
41
|
+
During the course of development, if new packages are added, it's recommended to update [`requirements.txt`](./requirements.txt) by running `pip freeze > requirements.txt`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Place integration API
|
|
2
|
+
|
|
3
|
+
This project contains a python API to connect MQTT data from Place devices to Place's Home Assistant integration
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
This repo utilizes VS Code [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) so you don't need to alter your global python environment.
|
|
8
|
+
|
|
9
|
+
## Installing dependencies
|
|
10
|
+
|
|
11
|
+
Use `pip` to install required dependencies by running `pip install -r requirements.txt` from the project root.
|
|
12
|
+
|
|
13
|
+
## Updating dependencies
|
|
14
|
+
|
|
15
|
+
During the course of development, if new packages are added, it's recommended to update [`requirements.txt`](./requirements.txt) by running `pip freeze > requirements.txt`.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "place-integration-api"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.6"
|
|
8
8
|
description = "Python APIs for Cognito-authenticated MQTT flows and Home Assistant discovery for Gentex Place."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -34,7 +34,9 @@ dev = [
|
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
[project.urls]
|
|
37
|
-
Homepage = "https://
|
|
37
|
+
Homepage = "https://placehomesolutions.com"
|
|
38
|
+
Issues = "https://placehomesolutions.com/support"
|
|
39
|
+
Repository = "https://github.com/Gentex-Corporation/place-integration-api"
|
|
38
40
|
|
|
39
41
|
[tool.pytest.ini_options]
|
|
40
42
|
testpaths = ["tests"]
|
|
@@ -25,9 +25,11 @@ class AbstractAuth(ABC):
|
|
|
25
25
|
access_token = await self.async_get_access_token()
|
|
26
26
|
headers["authorization"] = f"Bearer {access_token}"
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
resp = await self.websession.request(
|
|
29
29
|
method,
|
|
30
30
|
url,
|
|
31
31
|
**kwargs,
|
|
32
32
|
headers=headers,
|
|
33
33
|
)
|
|
34
|
+
resp.raise_for_status()
|
|
35
|
+
return resp
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from aiohttp import ContentTypeError
|
|
6
|
+
|
|
7
|
+
from .auth.abstract_auth import AbstractAuth
|
|
8
|
+
from .errors import PlaceFulfillmentError
|
|
9
|
+
from .models.discover_device import DiscoverDevice
|
|
10
|
+
from .config import FULFILLMENT_URL
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def _send_command(authorized_session: AbstractAuth, command: str) -> dict[str, Any]:
|
|
14
|
+
"""Send a fulfillment command and return the parsed response body."""
|
|
15
|
+
body = {"command": command, "data": {}}
|
|
16
|
+
resp = await authorized_session.request("POST", FULFILLMENT_URL, json=body)
|
|
17
|
+
try:
|
|
18
|
+
data = await resp.json()
|
|
19
|
+
except (ContentTypeError, ValueError) as err:
|
|
20
|
+
raise PlaceFulfillmentError(
|
|
21
|
+
f"Invalid response from fulfillment API: {err}"
|
|
22
|
+
) from err
|
|
23
|
+
if not isinstance(data, dict):
|
|
24
|
+
raise PlaceFulfillmentError(f"Invalid response from fulfillment API: {data!r}")
|
|
25
|
+
if not data.get("success", True):
|
|
26
|
+
raise PlaceFulfillmentError(f"Home Assistant error: {data.get('message', data)}")
|
|
27
|
+
return data
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Provider:
|
|
31
|
+
def __init__(self, authorized_session: AbstractAuth) -> None:
|
|
32
|
+
self.authorized_session = authorized_session
|
|
33
|
+
|
|
34
|
+
async def discover(self) -> list[DiscoverDevice]:
|
|
35
|
+
data = await _send_command(self.authorized_session, "DISCOVER")
|
|
36
|
+
devices_raw = (data.get("data") or {}).get("devices") or []
|
|
37
|
+
return [DiscoverDevice.from_dict(raw) for raw in devices_raw]
|
|
38
|
+
|
|
39
|
+
async def enable(self):
|
|
40
|
+
return await _send_command(self.authorized_session, "ENABLE")
|
|
41
|
+
|
|
42
|
+
async def disable(self):
|
|
43
|
+
return await _send_command(self.authorized_session, "DISABLE")
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: place-integration-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Python APIs for Cognito-authenticated MQTT flows and Home Assistant discovery for Gentex Place.
|
|
5
5
|
Author-email: Nicholas Aelick <niaexa@syntronic.com>, Andrew Tran <andrew.tran@gentex.com>
|
|
6
|
-
Project-URL: Homepage, https://
|
|
6
|
+
Project-URL: Homepage, https://placehomesolutions.com
|
|
7
|
+
Project-URL: Issues, https://placehomesolutions.com/support
|
|
8
|
+
Project-URL: Repository, https://github.com/Gentex-Corporation/place-integration-api
|
|
7
9
|
Classifier: Programming Language :: Python :: 3
|
|
8
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
9
11
|
Classifier: Operating System :: OS Independent
|
|
@@ -25,3 +27,15 @@ Dynamic: license-file
|
|
|
25
27
|
# Place integration API
|
|
26
28
|
|
|
27
29
|
This project contains a python API to connect MQTT data from Place devices to Place's Home Assistant integration
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
This repo utilizes VS Code [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) so you don't need to alter your global python environment.
|
|
34
|
+
|
|
35
|
+
## Installing dependencies
|
|
36
|
+
|
|
37
|
+
Use `pip` to install required dependencies by running `pip install -r requirements.txt` from the project root.
|
|
38
|
+
|
|
39
|
+
## Updating dependencies
|
|
40
|
+
|
|
41
|
+
During the course of development, if new packages are added, it's recommended to update [`requirements.txt`](./requirements.txt) by running `pip freeze > requirements.txt`.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from aiohttp import ClientResponseError
|
|
8
|
+
|
|
9
|
+
from place.auth import get_iot_credentials
|
|
10
|
+
from place.auth.abstract_auth import AbstractAuth
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class _FakeAuth(AbstractAuth):
|
|
14
|
+
async def async_get_access_token(self) -> str:
|
|
15
|
+
return "token"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@patch("place.auth.srp_auth.boto3")
|
|
19
|
+
def test_get_iot_credentials_success(mock_boto3: MagicMock) -> None:
|
|
20
|
+
identity_client = MagicMock()
|
|
21
|
+
mock_boto3.client.return_value = identity_client
|
|
22
|
+
|
|
23
|
+
identity_client.get_id.return_value = {"IdentityId": "identity-123"}
|
|
24
|
+
identity_client.get_credentials_for_identity.return_value = {
|
|
25
|
+
"Credentials": {
|
|
26
|
+
"AccessKeyId": "AKIA...",
|
|
27
|
+
"SecretKey": "secret",
|
|
28
|
+
"SessionToken": "session",
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
creds = get_iot_credentials(
|
|
34
|
+
id_token="id-token",
|
|
35
|
+
access_token="access-token",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
assert creds.access_key_id == "AKIA..."
|
|
39
|
+
assert creds.secret_access_key == "secret"
|
|
40
|
+
assert creds.session_token == "session"
|
|
41
|
+
assert creds.identity_id == "identity-123"
|
|
42
|
+
assert creds.access_token == "access-token"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_request_raises_for_non_2xx_status() -> None:
|
|
46
|
+
response = MagicMock()
|
|
47
|
+
response.raise_for_status.side_effect = ClientResponseError(
|
|
48
|
+
request_info=MagicMock(), history=(), status=401
|
|
49
|
+
)
|
|
50
|
+
websession = MagicMock()
|
|
51
|
+
websession.request = AsyncMock(return_value=response)
|
|
52
|
+
|
|
53
|
+
auth = _FakeAuth(websession)
|
|
54
|
+
|
|
55
|
+
with pytest.raises(ClientResponseError):
|
|
56
|
+
asyncio.run(auth.request("POST", "https://example.com"))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_request_returns_response_for_2xx_status() -> None:
|
|
60
|
+
response = MagicMock()
|
|
61
|
+
response.raise_for_status.return_value = None
|
|
62
|
+
websession = MagicMock()
|
|
63
|
+
websession.request = AsyncMock(return_value=response)
|
|
64
|
+
|
|
65
|
+
auth = _FakeAuth(websession)
|
|
66
|
+
|
|
67
|
+
result = asyncio.run(auth.request("POST", "https://example.com"))
|
|
68
|
+
|
|
69
|
+
assert result is response
|
|
70
|
+
response.raise_for_status.assert_called_once()
|
|
@@ -2,8 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
5
7
|
from place.auth.abstract_auth import AbstractAuth
|
|
6
8
|
from place.config import FULFILLMENT_URL
|
|
9
|
+
from place.errors import PlaceFulfillmentError
|
|
7
10
|
from place.provider import Provider
|
|
8
11
|
|
|
9
12
|
|
|
@@ -101,3 +104,79 @@ def test_provider_disable_sends_disable_command() -> None:
|
|
|
101
104
|
|
|
102
105
|
assert auth.calls == [("POST", FULFILLMENT_URL, {"json": {"command": "DISABLE", "data": {}}})]
|
|
103
106
|
assert result == payload
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_provider_discover_raises_on_success_false() -> None:
|
|
110
|
+
payload = {"success": False, "message": "not authorized"}
|
|
111
|
+
|
|
112
|
+
class DummyAuth(AbstractAuth):
|
|
113
|
+
async def async_get_access_token(self) -> str:
|
|
114
|
+
return "token"
|
|
115
|
+
|
|
116
|
+
async def request(self, method, url, **kwargs):
|
|
117
|
+
class DummyResponse:
|
|
118
|
+
async def json(self_inner):
|
|
119
|
+
return payload
|
|
120
|
+
|
|
121
|
+
return DummyResponse()
|
|
122
|
+
|
|
123
|
+
provider = Provider(DummyAuth(None))
|
|
124
|
+
|
|
125
|
+
with pytest.raises(PlaceFulfillmentError):
|
|
126
|
+
asyncio.run(provider.discover())
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_provider_enable_raises_on_success_false() -> None:
|
|
130
|
+
payload = {"success": False, "message": "not authorized"}
|
|
131
|
+
|
|
132
|
+
class DummyAuth(AbstractAuth):
|
|
133
|
+
async def async_get_access_token(self) -> str:
|
|
134
|
+
return "token"
|
|
135
|
+
|
|
136
|
+
async def request(self, method, url, **kwargs):
|
|
137
|
+
class DummyResponse:
|
|
138
|
+
async def json(self_inner):
|
|
139
|
+
return payload
|
|
140
|
+
|
|
141
|
+
return DummyResponse()
|
|
142
|
+
|
|
143
|
+
provider = Provider(DummyAuth(None))
|
|
144
|
+
|
|
145
|
+
with pytest.raises(PlaceFulfillmentError):
|
|
146
|
+
asyncio.run(provider.enable())
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_provider_raises_on_non_dict_response() -> None:
|
|
150
|
+
class DummyAuth(AbstractAuth):
|
|
151
|
+
async def async_get_access_token(self) -> str:
|
|
152
|
+
return "token"
|
|
153
|
+
|
|
154
|
+
async def request(self, method, url, **kwargs):
|
|
155
|
+
class DummyResponse:
|
|
156
|
+
async def json(self_inner):
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
return DummyResponse()
|
|
160
|
+
|
|
161
|
+
provider = Provider(DummyAuth(None))
|
|
162
|
+
|
|
163
|
+
with pytest.raises(PlaceFulfillmentError):
|
|
164
|
+
asyncio.run(provider.discover())
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_provider_raises_on_invalid_json_body() -> None:
|
|
168
|
+
class DummyAuth(AbstractAuth):
|
|
169
|
+
async def async_get_access_token(self) -> str:
|
|
170
|
+
return "token"
|
|
171
|
+
|
|
172
|
+
async def request(self, method, url, **kwargs):
|
|
173
|
+
class DummyResponse:
|
|
174
|
+
async def json(self_inner):
|
|
175
|
+
raise ValueError("Expecting value: line 1 column 1 (char 0)")
|
|
176
|
+
|
|
177
|
+
return DummyResponse()
|
|
178
|
+
|
|
179
|
+
provider = Provider(DummyAuth(None))
|
|
180
|
+
|
|
181
|
+
with pytest.raises(PlaceFulfillmentError):
|
|
182
|
+
asyncio.run(provider.discover())
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from .auth.abstract_auth import AbstractAuth
|
|
4
|
-
from .models.discover_device import DiscoverDevice
|
|
5
|
-
from .config import FULFILLMENT_URL
|
|
6
|
-
|
|
7
|
-
class Provider:
|
|
8
|
-
def __init__(self, authorized_session: AbstractAuth) -> None:
|
|
9
|
-
self.authorized_session = authorized_session
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
async def discover(self) -> list[DiscoverDevice]:
|
|
13
|
-
body = {"command": "DISCOVER", "data": {}}
|
|
14
|
-
resp = await self.authorized_session.request("POST", FULFILLMENT_URL, json=body)
|
|
15
|
-
data = await resp.json()
|
|
16
|
-
if not data.get("success", True):
|
|
17
|
-
raise RuntimeError(f"Home Assistant error: {data.get('message', data)}")
|
|
18
|
-
devices_raw = (data.get("data") or {}).get("devices") or []
|
|
19
|
-
devices: list[DiscoverDevice] = []
|
|
20
|
-
for raw in devices_raw:
|
|
21
|
-
devices.append(DiscoverDevice.from_dict(raw))
|
|
22
|
-
return devices
|
|
23
|
-
|
|
24
|
-
async def enable(self):
|
|
25
|
-
body = {"command": "ENABLE", "data": {}}
|
|
26
|
-
resp = await self.authorized_session.request("POST", FULFILLMENT_URL, json=body)
|
|
27
|
-
data = await resp.json()
|
|
28
|
-
if not data.get("success", True):
|
|
29
|
-
raise RuntimeError(f"Home Assistant error: {data.get('message', data)}")
|
|
30
|
-
return data
|
|
31
|
-
|
|
32
|
-
async def disable(self):
|
|
33
|
-
body = {"command": "DISABLE", "data": {}}
|
|
34
|
-
resp = await self.authorized_session.request("POST", FULFILLMENT_URL, json=body)
|
|
35
|
-
data = await resp.json()
|
|
36
|
-
if not data.get("success", True):
|
|
37
|
-
raise RuntimeError(f"Home Assistant error: {data.get('message', data)}")
|
|
38
|
-
return data
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from unittest.mock import MagicMock, patch
|
|
4
|
-
from place.auth import get_iot_credentials
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@patch("place.auth.srp_auth.boto3")
|
|
8
|
-
def test_get_iot_credentials_success(mock_boto3: MagicMock) -> None:
|
|
9
|
-
identity_client = MagicMock()
|
|
10
|
-
mock_boto3.client.return_value = identity_client
|
|
11
|
-
|
|
12
|
-
identity_client.get_id.return_value = {"IdentityId": "identity-123"}
|
|
13
|
-
identity_client.get_credentials_for_identity.return_value = {
|
|
14
|
-
"Credentials": {
|
|
15
|
-
"AccessKeyId": "AKIA...",
|
|
16
|
-
"SecretKey": "secret",
|
|
17
|
-
"SessionToken": "session",
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
creds = get_iot_credentials(
|
|
23
|
-
id_token="id-token",
|
|
24
|
-
access_token="access-token",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
assert creds.access_key_id == "AKIA..."
|
|
28
|
-
assert creds.secret_access_key == "secret"
|
|
29
|
-
assert creds.session_token == "session"
|
|
30
|
-
assert creds.identity_id == "identity-123"
|
|
31
|
-
assert creds.access_token == "access-token"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/device_shadow.py
RENAMED
|
File without changes
|
{place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/discover_device.py
RENAMED
|
File without changes
|
|
File without changes
|
{place_integration_api-0.2.4 → place_integration_api-0.2.6}/src/place/models/mqtt_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|