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
32 changes: 32 additions & 0 deletions aiohasupervisor/discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Discovery client for supervisor."""

from uuid import UUID

from .client import _SupervisorComponentClient
from .const import ResponseType
from .models.discovery import Discovery, DiscoveryConfig, DiscoveryList, SetDiscovery


class DiscoveryClient(_SupervisorComponentClient):
"""Handles discovery access in supervisor."""

async def list(self) -> list[Discovery]:
"""List discovered active services."""
result = await self._client.get("discovery")
return DiscoveryList.from_dict(result.data).discovery

async def get(self, uuid: UUID) -> Discovery:
"""Get discovery details for a service."""
result = await self._client.get(f"discovery/{uuid.hex}")
return Discovery.from_dict(result.data)

async def delete(self, uuid: UUID) -> None:
"""Remove discovery for a service."""
await self._client.delete(f"discovery/{uuid.hex}")

async def set(self, config: DiscoveryConfig) -> UUID:
"""Inform supervisor of an available service."""
result = await self._client.post(
"discovery", json=config.to_dict(), response_type=ResponseType.JSON
)
return SetDiscovery.from_dict(result.data).uuid
7 changes: 7 additions & 0 deletions aiohasupervisor/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
PartialBackupOptions,
PartialRestoreOptions,
)
from aiohasupervisor.models.discovery import (
Discovery,
DiscoveryConfig,
)
from aiohasupervisor.models.homeassistant import (
HomeAssistantInfo,
HomeAssistantOptions,
Expand Down Expand Up @@ -170,4 +174,7 @@
"NewBackup",
"PartialBackupOptions",
"PartialRestoreOptions",
"Discovery",
"DiscoveryConfig",
"DiscoveryList",
]
39 changes: 39 additions & 0 deletions aiohasupervisor/models/discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Models for discovery component."""

from dataclasses import dataclass
from typing import Any
from uuid import UUID

from .base import Request, ResponseData


@dataclass(frozen=True, slots=True)
class DiscoveryConfig(Request):
"""DiscoveryConfig model."""

service: str
config: dict[str, Any]


@dataclass(frozen=True, slots=True)
class Discovery(ResponseData):
"""Discovery model."""

addon: str
service: str
uuid: UUID
config: dict[str, Any]


@dataclass(frozen=True, slots=True)
class DiscoveryList(ResponseData):
"""DiscoveryList model."""

discovery: list[Discovery]


@dataclass(frozen=True, slots=True)
class SetDiscovery(ResponseData):
"""SetDiscovery model."""

uuid: UUID
7 changes: 7 additions & 0 deletions aiohasupervisor/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .addons import AddonsClient
from .backups import BackupsClient
from .client import _SupervisorClient
from .discovery import DiscoveryClient
from .homeassistant import HomeAssistantClient
from .models.root import AvailableUpdate, AvailableUpdates, RootInfo
from .os import OSClient
Expand All @@ -30,6 +31,7 @@ def __init__(
self._addons = AddonsClient(self._client)
self._os = OSClient(self._client)
self._backups = BackupsClient(self._client)
self._discovery = DiscoveryClient(self._client)
self._resolution = ResolutionClient(self._client)
self._store = StoreClient(self._client)
self._supervisor = SupervisorManagementClient(self._client)
Expand All @@ -55,6 +57,11 @@ def backups(self) -> BackupsClient:
"""Get backups component client."""
return self._backups

@property
def discovery(self) -> DiscoveryClient:
"""Get discovery component client."""
return self._discovery

@property
def resolution(self) -> ResolutionClient:
"""Get resolution center component client."""
Expand Down
16 changes: 16 additions & 0 deletions tests/fixtures/discovery_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"result": "ok",
"data": {
"addon": "core_mosquitto",
"service": "mqtt",
"uuid": "889ca604cff84004894e53d181655b3a",
"config": {
"host": "core-mosquitto",
"port": 1883,
"ssl": false,
"protocol": "3.1.1",
"username": "homeassistant",
"password": "abc123"
}
}
}
45 changes: 45 additions & 0 deletions tests/fixtures/discovery_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"result": "ok",
"data": {
"discovery": [
{
"addon": "core_mosquitto",
"service": "mqtt",
"uuid": "889ca604cff84004894e53d181655b3a",
"config": {
"host": "core-mosquitto",
"port": 1883,
"ssl": false,
"protocol": "3.1.1",
"username": "homeassistant",
"password": "abc123"
}
}
],
"services": {
"vlc_telnet": ["core_vlc"],
"esphome": [
"5c53de3b_esphome-beta",
"5c53de3b_esphome-dev",
"5c53de3b_esphome"
],
"zwave_js": [
"core_zwave_js",
"a0d7b954_zwavejs2mqtt",
"77f1785d_zwave_mock_server"
],
"matter": ["core_matter_server"],
"wyoming": [
"core_whisper",
"core_assist_microphone",
"core_piper",
"core_openwakeword"
],
"otbr": ["core_openthread_border_router", "core_silabs_multiprotocol"],
"mqtt": ["core_mosquitto"],
"motioneye": ["a0d7b954_motioneye"],
"deconz": ["core_deconz"],
"adguard": ["a0d7b954_adguard"]
}
}
}
6 changes: 6 additions & 0 deletions tests/fixtures/discovery_set.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"result": "ok",
"data": {
"uuid": "889ca604cff84004894e53d181655b3a"
}
}
73 changes: 73 additions & 0 deletions tests/test_discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Test discovery supervisor client."""

from uuid import UUID

from aioresponses import aioresponses
from yarl import URL

from aiohasupervisor import SupervisorClient
from aiohasupervisor.models import DiscoveryConfig

from . import load_fixture
from .const import SUPERVISOR_URL


async def test_discovery_list(
responses: aioresponses, supervisor_client: SupervisorClient
) -> None:
"""Test Discovery list API."""
responses.get(
f"{SUPERVISOR_URL}/discovery",
status=200,
body=load_fixture("discovery_list.json"),
)
disc_list = await supervisor_client.discovery.list()
assert disc_list[0].addon == "core_mosquitto"
assert disc_list[0].service == "mqtt"
assert disc_list[0].uuid.hex == "889ca604cff84004894e53d181655b3a"
assert disc_list[0].config["host"] == "core-mosquitto"


async def test_get_discovery(
responses: aioresponses, supervisor_client: SupervisorClient
) -> None:
"""Test Discovery get API."""
uuid = UUID("889ca604cff84004894e53d181655b3a")
responses.get(
f"{SUPERVISOR_URL}/discovery/{uuid.hex}",
status=200,
body=load_fixture("discovery_get.json"),
)
discovery = await supervisor_client.discovery.get(uuid)
assert discovery.addon == "core_mosquitto"
assert discovery.service == "mqtt"
assert discovery.uuid == uuid
assert discovery.config["host"] == "core-mosquitto"
assert discovery.config["port"] == 1883
assert discovery.config["ssl"] is False


async def test_delete_discovery(
responses: aioresponses, supervisor_client: SupervisorClient
) -> None:
"""Test Discovery delete API."""
uuid = UUID("889ca604cff84004894e53d181655b3a")
responses.delete(f"{SUPERVISOR_URL}/discovery/{uuid.hex}", status=200)
assert await supervisor_client.discovery.delete(uuid) is None
assert responses.requests.keys() == {
("DELETE", URL(f"{SUPERVISOR_URL}/discovery/{uuid.hex}"))
}


async def test_set_discovery(
responses: aioresponses, supervisor_client: SupervisorClient
) -> None:
"""Test Discovery set API."""
responses.post(
f"{SUPERVISOR_URL}/discovery",
status=200,
body=load_fixture("discovery_set.json"),
)
assert await supervisor_client.discovery.set(
DiscoveryConfig(service="mqtt", config={})
) == UUID("889ca604cff84004894e53d181655b3a")
Loading