Skip to content

Commit 0d82742

Browse files
authored
Add discovery APIs from supervisor (#16)
* Add discovery APIs from supervisor * Remove services and simply list discovery
1 parent 4f8de4d commit 0d82742

File tree

8 files changed

+225
-0
lines changed

8 files changed

+225
-0
lines changed

aiohasupervisor/discovery.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Discovery client for supervisor."""
2+
3+
from uuid import UUID
4+
5+
from .client import _SupervisorComponentClient
6+
from .const import ResponseType
7+
from .models.discovery import Discovery, DiscoveryConfig, DiscoveryList, SetDiscovery
8+
9+
10+
class DiscoveryClient(_SupervisorComponentClient):
11+
"""Handles discovery access in supervisor."""
12+
13+
async def list(self) -> list[Discovery]:
14+
"""List discovered active services."""
15+
result = await self._client.get("discovery")
16+
return DiscoveryList.from_dict(result.data).discovery
17+
18+
async def get(self, uuid: UUID) -> Discovery:
19+
"""Get discovery details for a service."""
20+
result = await self._client.get(f"discovery/{uuid.hex}")
21+
return Discovery.from_dict(result.data)
22+
23+
async def delete(self, uuid: UUID) -> None:
24+
"""Remove discovery for a service."""
25+
await self._client.delete(f"discovery/{uuid.hex}")
26+
27+
async def set(self, config: DiscoveryConfig) -> UUID:
28+
"""Inform supervisor of an available service."""
29+
result = await self._client.post(
30+
"discovery", json=config.to_dict(), response_type=ResponseType.JSON
31+
)
32+
return SetDiscovery.from_dict(result.data).uuid

aiohasupervisor/models/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
PartialBackupOptions,
4141
PartialRestoreOptions,
4242
)
43+
from aiohasupervisor.models.discovery import (
44+
Discovery,
45+
DiscoveryConfig,
46+
)
4347
from aiohasupervisor.models.homeassistant import (
4448
HomeAssistantInfo,
4549
HomeAssistantOptions,
@@ -170,4 +174,7 @@
170174
"NewBackup",
171175
"PartialBackupOptions",
172176
"PartialRestoreOptions",
177+
"Discovery",
178+
"DiscoveryConfig",
179+
"DiscoveryList",
173180
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Models for discovery component."""
2+
3+
from dataclasses import dataclass
4+
from typing import Any
5+
from uuid import UUID
6+
7+
from .base import Request, ResponseData
8+
9+
10+
@dataclass(frozen=True, slots=True)
11+
class DiscoveryConfig(Request):
12+
"""DiscoveryConfig model."""
13+
14+
service: str
15+
config: dict[str, Any]
16+
17+
18+
@dataclass(frozen=True, slots=True)
19+
class Discovery(ResponseData):
20+
"""Discovery model."""
21+
22+
addon: str
23+
service: str
24+
uuid: UUID
25+
config: dict[str, Any]
26+
27+
28+
@dataclass(frozen=True, slots=True)
29+
class DiscoveryList(ResponseData):
30+
"""DiscoveryList model."""
31+
32+
discovery: list[Discovery]
33+
34+
35+
@dataclass(frozen=True, slots=True)
36+
class SetDiscovery(ResponseData):
37+
"""SetDiscovery model."""
38+
39+
uuid: UUID

aiohasupervisor/root.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .addons import AddonsClient
88
from .backups import BackupsClient
99
from .client import _SupervisorClient
10+
from .discovery import DiscoveryClient
1011
from .homeassistant import HomeAssistantClient
1112
from .models.root import AvailableUpdate, AvailableUpdates, RootInfo
1213
from .os import OSClient
@@ -30,6 +31,7 @@ def __init__(
3031
self._addons = AddonsClient(self._client)
3132
self._os = OSClient(self._client)
3233
self._backups = BackupsClient(self._client)
34+
self._discovery = DiscoveryClient(self._client)
3335
self._resolution = ResolutionClient(self._client)
3436
self._store = StoreClient(self._client)
3537
self._supervisor = SupervisorManagementClient(self._client)
@@ -55,6 +57,11 @@ def backups(self) -> BackupsClient:
5557
"""Get backups component client."""
5658
return self._backups
5759

60+
@property
61+
def discovery(self) -> DiscoveryClient:
62+
"""Get discovery component client."""
63+
return self._discovery
64+
5865
@property
5966
def resolution(self) -> ResolutionClient:
6067
"""Get resolution center component client."""

tests/fixtures/discovery_get.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"result": "ok",
3+
"data": {
4+
"addon": "core_mosquitto",
5+
"service": "mqtt",
6+
"uuid": "889ca604cff84004894e53d181655b3a",
7+
"config": {
8+
"host": "core-mosquitto",
9+
"port": 1883,
10+
"ssl": false,
11+
"protocol": "3.1.1",
12+
"username": "homeassistant",
13+
"password": "abc123"
14+
}
15+
}
16+
}

tests/fixtures/discovery_list.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"result": "ok",
3+
"data": {
4+
"discovery": [
5+
{
6+
"addon": "core_mosquitto",
7+
"service": "mqtt",
8+
"uuid": "889ca604cff84004894e53d181655b3a",
9+
"config": {
10+
"host": "core-mosquitto",
11+
"port": 1883,
12+
"ssl": false,
13+
"protocol": "3.1.1",
14+
"username": "homeassistant",
15+
"password": "abc123"
16+
}
17+
}
18+
],
19+
"services": {
20+
"vlc_telnet": ["core_vlc"],
21+
"esphome": [
22+
"5c53de3b_esphome-beta",
23+
"5c53de3b_esphome-dev",
24+
"5c53de3b_esphome"
25+
],
26+
"zwave_js": [
27+
"core_zwave_js",
28+
"a0d7b954_zwavejs2mqtt",
29+
"77f1785d_zwave_mock_server"
30+
],
31+
"matter": ["core_matter_server"],
32+
"wyoming": [
33+
"core_whisper",
34+
"core_assist_microphone",
35+
"core_piper",
36+
"core_openwakeword"
37+
],
38+
"otbr": ["core_openthread_border_router", "core_silabs_multiprotocol"],
39+
"mqtt": ["core_mosquitto"],
40+
"motioneye": ["a0d7b954_motioneye"],
41+
"deconz": ["core_deconz"],
42+
"adguard": ["a0d7b954_adguard"]
43+
}
44+
}
45+
}

tests/fixtures/discovery_set.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"result": "ok",
3+
"data": {
4+
"uuid": "889ca604cff84004894e53d181655b3a"
5+
}
6+
}

tests/test_discovery.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Test discovery supervisor client."""
2+
3+
from uuid import UUID
4+
5+
from aioresponses import aioresponses
6+
from yarl import URL
7+
8+
from aiohasupervisor import SupervisorClient
9+
from aiohasupervisor.models import DiscoveryConfig
10+
11+
from . import load_fixture
12+
from .const import SUPERVISOR_URL
13+
14+
15+
async def test_discovery_list(
16+
responses: aioresponses, supervisor_client: SupervisorClient
17+
) -> None:
18+
"""Test Discovery list API."""
19+
responses.get(
20+
f"{SUPERVISOR_URL}/discovery",
21+
status=200,
22+
body=load_fixture("discovery_list.json"),
23+
)
24+
disc_list = await supervisor_client.discovery.list()
25+
assert disc_list[0].addon == "core_mosquitto"
26+
assert disc_list[0].service == "mqtt"
27+
assert disc_list[0].uuid.hex == "889ca604cff84004894e53d181655b3a"
28+
assert disc_list[0].config["host"] == "core-mosquitto"
29+
30+
31+
async def test_get_discovery(
32+
responses: aioresponses, supervisor_client: SupervisorClient
33+
) -> None:
34+
"""Test Discovery get API."""
35+
uuid = UUID("889ca604cff84004894e53d181655b3a")
36+
responses.get(
37+
f"{SUPERVISOR_URL}/discovery/{uuid.hex}",
38+
status=200,
39+
body=load_fixture("discovery_get.json"),
40+
)
41+
discovery = await supervisor_client.discovery.get(uuid)
42+
assert discovery.addon == "core_mosquitto"
43+
assert discovery.service == "mqtt"
44+
assert discovery.uuid == uuid
45+
assert discovery.config["host"] == "core-mosquitto"
46+
assert discovery.config["port"] == 1883
47+
assert discovery.config["ssl"] is False
48+
49+
50+
async def test_delete_discovery(
51+
responses: aioresponses, supervisor_client: SupervisorClient
52+
) -> None:
53+
"""Test Discovery delete API."""
54+
uuid = UUID("889ca604cff84004894e53d181655b3a")
55+
responses.delete(f"{SUPERVISOR_URL}/discovery/{uuid.hex}", status=200)
56+
assert await supervisor_client.discovery.delete(uuid) is None
57+
assert responses.requests.keys() == {
58+
("DELETE", URL(f"{SUPERVISOR_URL}/discovery/{uuid.hex}"))
59+
}
60+
61+
62+
async def test_set_discovery(
63+
responses: aioresponses, supervisor_client: SupervisorClient
64+
) -> None:
65+
"""Test Discovery set API."""
66+
responses.post(
67+
f"{SUPERVISOR_URL}/discovery",
68+
status=200,
69+
body=load_fixture("discovery_set.json"),
70+
)
71+
assert await supervisor_client.discovery.set(
72+
DiscoveryConfig(service="mqtt", config={})
73+
) == UUID("889ca604cff84004894e53d181655b3a")

0 commit comments

Comments
 (0)