mirror of
https://github.com/home-assistant/core.git
synced 2025-04-28 11:17:53 +00:00
Add button platform to pyLoad integration (#120359)
This commit is contained in:
parent
adc074f60a
commit
fd0fee1900
@ -22,7 +22,7 @@ from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
|||||||
|
|
||||||
from .coordinator import PyLoadCoordinator
|
from .coordinator import PyLoadCoordinator
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
PLATFORMS: list[Platform] = [Platform.BUTTON, Platform.SENSOR]
|
||||||
|
|
||||||
type PyLoadConfigEntry = ConfigEntry[PyLoadCoordinator]
|
type PyLoadConfigEntry = ConfigEntry[PyLoadCoordinator]
|
||||||
|
|
||||||
|
107
homeassistant/components/pyload/button.py
Normal file
107
homeassistant/components/pyload/button.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
"""Support for monitoring pyLoad."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import StrEnum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pyloadapi.api import PyLoadAPI
|
||||||
|
|
||||||
|
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from . import PyLoadConfigEntry
|
||||||
|
from .const import DOMAIN, MANUFACTURER, SERVICE_NAME
|
||||||
|
from .coordinator import PyLoadCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(kw_only=True, frozen=True)
|
||||||
|
class PyLoadButtonEntityDescription(ButtonEntityDescription):
|
||||||
|
"""Describes pyLoad button entity."""
|
||||||
|
|
||||||
|
press_fn: Callable[[PyLoadAPI], Awaitable[Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class PyLoadButtonEntity(StrEnum):
|
||||||
|
"""PyLoad button Entities."""
|
||||||
|
|
||||||
|
ABORT_DOWNLOADS = "abort_downloads"
|
||||||
|
RESTART_FAILED = "restart_failed"
|
||||||
|
DELETE_FINISHED = "delete_finished"
|
||||||
|
RESTART = "restart"
|
||||||
|
|
||||||
|
|
||||||
|
SENSOR_DESCRIPTIONS: tuple[PyLoadButtonEntityDescription, ...] = (
|
||||||
|
PyLoadButtonEntityDescription(
|
||||||
|
key=PyLoadButtonEntity.ABORT_DOWNLOADS,
|
||||||
|
translation_key=PyLoadButtonEntity.ABORT_DOWNLOADS,
|
||||||
|
press_fn=lambda api: api.stop_all_downloads(),
|
||||||
|
),
|
||||||
|
PyLoadButtonEntityDescription(
|
||||||
|
key=PyLoadButtonEntity.RESTART_FAILED,
|
||||||
|
translation_key=PyLoadButtonEntity.RESTART_FAILED,
|
||||||
|
press_fn=lambda api: api.restart_failed(),
|
||||||
|
),
|
||||||
|
PyLoadButtonEntityDescription(
|
||||||
|
key=PyLoadButtonEntity.DELETE_FINISHED,
|
||||||
|
translation_key=PyLoadButtonEntity.DELETE_FINISHED,
|
||||||
|
press_fn=lambda api: api.delete_finished(),
|
||||||
|
),
|
||||||
|
PyLoadButtonEntityDescription(
|
||||||
|
key=PyLoadButtonEntity.RESTART,
|
||||||
|
translation_key=PyLoadButtonEntity.RESTART,
|
||||||
|
press_fn=lambda api: api.restart(),
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: PyLoadConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up buttons from a config entry."""
|
||||||
|
|
||||||
|
coordinator = entry.runtime_data
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
PyLoadBinarySensor(coordinator, description)
|
||||||
|
for description in SENSOR_DESCRIPTIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PyLoadBinarySensor(CoordinatorEntity[PyLoadCoordinator], ButtonEntity):
|
||||||
|
"""Representation of a pyLoad button."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
entity_description: PyLoadButtonEntityDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: PyLoadCoordinator,
|
||||||
|
entity_description: PyLoadButtonEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the button."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self._attr_unique_id = (
|
||||||
|
f"{coordinator.config_entry.entry_id}_{entity_description.key}"
|
||||||
|
)
|
||||||
|
self.entity_description = entity_description
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
|
manufacturer=MANUFACTURER,
|
||||||
|
model=SERVICE_NAME,
|
||||||
|
configuration_url=coordinator.pyload.api_url,
|
||||||
|
identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
|
||||||
|
translation_key=DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_press(self) -> None:
|
||||||
|
"""Handle the button press."""
|
||||||
|
await self.entity_description.press_fn(self.coordinator.pyload)
|
@ -7,3 +7,6 @@ DEFAULT_NAME = "pyLoad"
|
|||||||
DEFAULT_PORT = 8000
|
DEFAULT_PORT = 8000
|
||||||
|
|
||||||
ISSUE_PLACEHOLDER = {"url": "/config/integrations/dashboard/add?domain=pyload"}
|
ISSUE_PLACEHOLDER = {"url": "/config/integrations/dashboard/add?domain=pyload"}
|
||||||
|
|
||||||
|
MANUFACTURER = "pyLoad Team"
|
||||||
|
SERVICE_NAME = "pyLoad"
|
||||||
|
@ -1,5 +1,19 @@
|
|||||||
{
|
{
|
||||||
"entity": {
|
"entity": {
|
||||||
|
"button": {
|
||||||
|
"abort_downloads": {
|
||||||
|
"default": "mdi:stop"
|
||||||
|
},
|
||||||
|
"restart_failed": {
|
||||||
|
"default": "mdi:cached"
|
||||||
|
},
|
||||||
|
"delete_finished": {
|
||||||
|
"default": "mdi:trash-can"
|
||||||
|
},
|
||||||
|
"restart": {
|
||||||
|
"default": "mdi:restart"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"speed": {
|
"speed": {
|
||||||
"default": "mdi:speedometer"
|
"default": "mdi:speedometer"
|
||||||
|
@ -28,6 +28,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entity": {
|
"entity": {
|
||||||
|
"button": {
|
||||||
|
"abort_downloads": {
|
||||||
|
"name": "Abort all running downloads"
|
||||||
|
},
|
||||||
|
"restart_failed": {
|
||||||
|
"name": "Restart all failed files"
|
||||||
|
},
|
||||||
|
"delete_finished": {
|
||||||
|
"name": "Delete finished files/packages"
|
||||||
|
},
|
||||||
|
"restart": {
|
||||||
|
"name": "Restart pyload core"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"speed": {
|
"speed": {
|
||||||
"name": "Speed"
|
"name": "Speed"
|
||||||
|
185
tests/components/pyload/snapshots/test_button.ambr
Normal file
185
tests/components/pyload/snapshots/test_button.ambr
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_state[button.pyload_abort_all_running_downloads-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'button',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'button.pyload_abort_all_running_downloads',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Abort all running downloads',
|
||||||
|
'platform': 'pyload',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': <PyLoadButtonEntity.ABORT_DOWNLOADS: 'abort_downloads'>,
|
||||||
|
'unique_id': 'XXXXXXXXXXXXXX_abort_downloads',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_abort_all_running_downloads-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'pyload Abort all running downloads',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'button.pyload_abort_all_running_downloads',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unknown',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_delete_finished_files_packages-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'button',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'button.pyload_delete_finished_files_packages',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Delete finished files/packages',
|
||||||
|
'platform': 'pyload',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': <PyLoadButtonEntity.DELETE_FINISHED: 'delete_finished'>,
|
||||||
|
'unique_id': 'XXXXXXXXXXXXXX_delete_finished',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_delete_finished_files_packages-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'pyload Delete finished files/packages',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'button.pyload_delete_finished_files_packages',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unknown',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_restart_all_failed_files-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'button',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'button.pyload_restart_all_failed_files',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Restart all failed files',
|
||||||
|
'platform': 'pyload',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': <PyLoadButtonEntity.RESTART_FAILED: 'restart_failed'>,
|
||||||
|
'unique_id': 'XXXXXXXXXXXXXX_restart_failed',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_restart_all_failed_files-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'pyload Restart all failed files',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'button.pyload_restart_all_failed_files',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unknown',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_restart_pyload_core-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'button',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'button.pyload_restart_pyload_core',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Restart pyload core',
|
||||||
|
'platform': 'pyload',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': <PyLoadButtonEntity.RESTART: 'restart'>,
|
||||||
|
'unique_id': 'XXXXXXXXXXXXXX_restart',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_state[button.pyload_restart_pyload_core-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'pyload Restart pyload core',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'button.pyload_restart_pyload_core',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unknown',
|
||||||
|
})
|
||||||
|
# ---
|
83
tests/components/pyload/test_button.py
Normal file
83
tests/components/pyload/test_button.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
"""The tests for the button component."""
|
||||||
|
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
|
from unittest.mock import AsyncMock, call, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||||
|
from homeassistant.components.pyload.button import PyLoadButtonEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
|
||||||
|
API_CALL = {
|
||||||
|
PyLoadButtonEntity.ABORT_DOWNLOADS: call.stop_all_downloads,
|
||||||
|
PyLoadButtonEntity.RESTART_FAILED: call.restart_failed,
|
||||||
|
PyLoadButtonEntity.DELETE_FINISHED: call.delete_finished,
|
||||||
|
PyLoadButtonEntity.RESTART: call.restart,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
async def button_only() -> AsyncGenerator[None, None]:
|
||||||
|
"""Enable only the button platform."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.pyload.PLATFORMS",
|
||||||
|
[Platform.BUTTON],
|
||||||
|
):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
|
async def test_state(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
mock_pyloadapi: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test button state."""
|
||||||
|
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
|
async def test_button_press(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
mock_pyloadapi: AsyncMock,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test switch turn on method."""
|
||||||
|
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
entity_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for entity_entry in entity_entries:
|
||||||
|
await hass.services.async_call(
|
||||||
|
BUTTON_DOMAIN,
|
||||||
|
SERVICE_PRESS,
|
||||||
|
{ATTR_ENTITY_ID: entity_entry.entity_id},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert API_CALL[entity_entry.translation_key] in mock_pyloadapi.method_calls
|
||||||
|
mock_pyloadapi.reset_mock()
|
@ -1,6 +1,7 @@
|
|||||||
"""Tests for the pyLoad Sensors."""
|
"""Tests for the pyLoad Sensors."""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock
|
from collections.abc import AsyncGenerator
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
from pyloadapi.exceptions import CannotConnect, InvalidAuth, ParserError
|
from pyloadapi.exceptions import CannotConnect, InvalidAuth, ParserError
|
||||||
@ -11,6 +12,7 @@ from homeassistant.components.pyload.const import DOMAIN
|
|||||||
from homeassistant.components.pyload.coordinator import SCAN_INTERVAL
|
from homeassistant.components.pyload.coordinator import SCAN_INTERVAL
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
@ -19,6 +21,16 @@ from homeassistant.setup import async_setup_component
|
|||||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
async def sensor_only() -> AsyncGenerator[None, None]:
|
||||||
|
"""Enable only the sensor platform."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.pyload.PLATFORMS",
|
||||||
|
[Platform.SENSOR],
|
||||||
|
):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
async def test_setup(
|
async def test_setup(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user