Cleanup tplink test framework (#135205)

This commit is contained in:
Steven B. 2025-01-13 18:32:22 +00:00 committed by GitHub
parent d986fe7a07
commit ab28115d2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 693 additions and 464 deletions

View File

@ -6,174 +6,36 @@ from datetime import datetime
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from kasa import (
BaseProtocol,
Device,
DeviceConfig,
DeviceConnectionParameters,
DeviceEncryptionType,
DeviceFamily,
DeviceType,
Feature,
KasaException,
Module,
)
from kasa import BaseProtocol, Device, DeviceType, Feature, KasaException, Module
from kasa.interfaces import Fan, Light, LightEffect, LightState
from kasa.smart.modules.alarm import Alarm
from kasa.smartcam.modules.camera import LOCAL_STREAMING_PORT, Camera
from syrupy import SnapshotAssertion
from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN
from homeassistant.components.tplink import (
CONF_AES_KEYS,
CONF_ALIAS,
CONF_CAMERA_CREDENTIALS,
CONF_CONNECTION_PARAMETERS,
CONF_CREDENTIALS_HASH,
CONF_HOST,
CONF_LIVE_VIEW,
CONF_MODEL,
CONF_USES_HTTP,
Credentials,
)
from homeassistant.components.tplink.const import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.const import CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.translation import async_get_translations
from homeassistant.helpers.typing import UNDEFINED
from homeassistant.setup import async_setup_component
from .const import (
ALIAS,
CREDENTIALS_HASH_LEGACY,
DEVICE_CONFIG_LEGACY,
DEVICE_ID,
IP_ADDRESS,
MAC_ADDRESS,
MODEL,
)
from tests.common import MockConfigEntry, load_json_value_fixture
ColorTempRange = namedtuple("ColorTempRange", ["min", "max"]) # noqa: PYI024
MODULE = "homeassistant.components.tplink"
MODULE_CONFIG_FLOW = "homeassistant.components.tplink.config_flow"
IP_ADDRESS = "127.0.0.1"
IP_ADDRESS2 = "127.0.0.2"
IP_ADDRESS3 = "127.0.0.3"
ALIAS = "My Bulb"
ALIAS_CAMERA = "My Camera"
MODEL = "HS100"
MODEL_CAMERA = "C210"
MAC_ADDRESS = "aa:bb:cc:dd:ee:ff"
DEVICE_ID = "123456789ABCDEFGH"
DEVICE_ID_MAC = "AA:BB:CC:DD:EE:FF"
DHCP_FORMATTED_MAC_ADDRESS = MAC_ADDRESS.replace(":", "")
MAC_ADDRESS2 = "11:22:33:44:55:66"
MAC_ADDRESS3 = "66:55:44:33:22:11"
DEFAULT_ENTRY_TITLE = f"{ALIAS} {MODEL}"
DEFAULT_ENTRY_TITLE_CAMERA = f"{ALIAS_CAMERA} {MODEL_CAMERA}"
CREDENTIALS_HASH_LEGACY = ""
CONN_PARAMS_LEGACY = DeviceConnectionParameters(
DeviceFamily.IotSmartPlugSwitch, DeviceEncryptionType.Xor
)
DEVICE_CONFIG_LEGACY = DeviceConfig(IP_ADDRESS)
DEVICE_CONFIG_DICT_LEGACY = {
k: v for k, v in DEVICE_CONFIG_LEGACY.to_dict().items() if k != "credentials"
}
CREDENTIALS = Credentials("foo", "bar")
CREDENTIALS_HASH_AES = "AES/abcdefghijklmnopqrstuvabcdefghijklmnopqrstuv=="
CREDENTIALS_HASH_KLAP = "KLAP/abcdefghijklmnopqrstuv=="
CONN_PARAMS_KLAP = DeviceConnectionParameters(
DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Klap
)
DEVICE_CONFIG_KLAP = DeviceConfig(
IP_ADDRESS,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_KLAP,
uses_http=True,
)
CONN_PARAMS_AES = DeviceConnectionParameters(
DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Aes
)
_test_privkey = (
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKLJKmBWGj6WYo9sewI8vkqar"
"Ed5H1JUr8Jj/LEWLTtV6+Mm4mfyEk6YKFHSmIG4AGgrVsGK/EbEkTZk9CwtixNQpBVc36oN2R"
"vuWWV38YnP4vI63mNxTA/gQonCsahjN4HfwE87pM7O5z39aeunoYm6Be663t33DbJH1ZUbZjm"
"tAgMBAAECgYB1Bn1KaFvRprcQOIJt51E9vNghQbf8rhj0fIEKpdC6mVhNIoUdCO+URNqnh+hP"
"SQIx4QYreUlHbsSeABFxOQSDJm6/kqyQsp59nCVDo/bXTtlvcSJ/sU3riqJNxYqEU1iJ0xMvU"
"N1VKKTmik89J8e5sN9R0AFfUSJIk7MpdOoD2QJBANTbV27nenyvbqee/ul4frdt2rrPGcGpcV"
"QmY87qbbrZgqgL5LMHHD7T/v/I8D1wRog1sBz/AiZGcnv/ox8dHKsCQQDDx8DCGPySSVqKVua"
"yUkBNpglN83wiCXZjyEtWIt+aB1A2n5ektE/o8oHnnOuvMdooxvtid7Mdapi2VLHV7VMHAkAE"
"d0GjWwnv2cJpk+VnQpbuBEkFiFjS/loZWODZM4Pv2qZqHi3DL9AA5XPBLBcWQufH7dBvG06RP"
"QMj5N4oRfUXAkEAuJJkVliqHNvM4OkGewzyFII4+WVYHNqg43dcFuuvtA27AJQ6qYtYXrvp3k"
"phI3yzOIhHTNCea1goepSkR5ODFwJBAJCTRbB+P47aEr/xA51ZFHE6VefDBJG9yg6yK4jcOxg"
"5ficXEpx8442okNtlzwa+QHpm/L3JOFrHwiEeVqXtiqY="
)
_test_pubkey = (
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiySpgVho+lmKPbHsCPL5KmqxHeR9SVK/CY"
"/yxFi07VevjJuJn8hJOmChR0piBuABoK1bBivxGxJE2ZPQsLYsTUKQVXN+qDdkb7llld/GJz+"
"LyOt5jcUwP4EKJwrGoYzeB38BPO6TOzuc9/Wnrp6GJugXuut7d9w2yR9WVG2Y5rQIDAQAB"
)
AES_KEYS = {"private": _test_privkey, "public": _test_pubkey}
DEVICE_CONFIG_AES = DeviceConfig(
IP_ADDRESS2,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_AES,
uses_http=True,
aes_keys=AES_KEYS,
)
CONN_PARAMS_AES_CAMERA = DeviceConnectionParameters(
DeviceFamily.SmartIpCamera, DeviceEncryptionType.Aes, https=True, login_version=2
)
DEVICE_CONFIG_AES_CAMERA = DeviceConfig(
IP_ADDRESS3,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_AES_CAMERA,
uses_http=True,
)
DEVICE_CONFIG_DICT_KLAP = {
k: v for k, v in DEVICE_CONFIG_KLAP.to_dict().items() if k != "credentials"
}
DEVICE_CONFIG_DICT_AES = {
k: v for k, v in DEVICE_CONFIG_AES.to_dict().items() if k != "credentials"
}
CREATE_ENTRY_DATA_LEGACY = {
CONF_HOST: IP_ADDRESS,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_LEGACY.to_dict(),
CONF_USES_HTTP: False,
}
CREATE_ENTRY_DATA_KLAP = {
CONF_HOST: IP_ADDRESS,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_KLAP,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_KLAP.to_dict(),
CONF_USES_HTTP: True,
}
CREATE_ENTRY_DATA_AES = {
CONF_HOST: IP_ADDRESS2,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES.to_dict(),
CONF_USES_HTTP: True,
CONF_AES_KEYS: AES_KEYS,
}
CREATE_ENTRY_DATA_AES_CAMERA = {
CONF_HOST: IP_ADDRESS3,
CONF_ALIAS: ALIAS_CAMERA,
CONF_MODEL: MODEL_CAMERA,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES_CAMERA.to_dict(),
CONF_USES_HTTP: True,
CONF_LIVE_VIEW: True,
CONF_CAMERA_CREDENTIALS: {"username": "camuser", "password": "campass"},
}
SMALLEST_VALID_JPEG = (
"ffd8ffe000104a46494600010101004800480000ffdb00430003020202020203020202030303030406040404040408060"
"6050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b08000100"
"0101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9"
)
SMALLEST_VALID_JPEG_BYTES = bytes.fromhex(SMALLEST_VALID_JPEG)
def _load_feature_fixtures():
fixtures = load_json_value_fixture("features.json", DOMAIN)
@ -201,7 +63,7 @@ async def setup_platform_for_device(
_patch_discovery(device=device),
_patch_connect(device=device),
):
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
# Good practice to wait background tasks in tests see PR #112726
await hass.async_block_till_done(wait_background_tasks=True)

View File

@ -10,7 +10,8 @@ import pytest
from homeassistant.components.tplink import DOMAIN
from homeassistant.core import HomeAssistant
from . import (
from . import _mocked_device
from .const import (
ALIAS_CAMERA,
CREATE_ENTRY_DATA_AES_CAMERA,
CREATE_ENTRY_DATA_LEGACY,
@ -26,7 +27,6 @@ from . import (
MAC_ADDRESS2,
MAC_ADDRESS3,
MODEL_CAMERA,
_mocked_device,
)
from tests.common import MockConfigEntry
@ -115,8 +115,12 @@ def mock_setup_entry() -> Generator[AsyncMock]:
@pytest.fixture
def mock_init() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
def mock_init() -> Generator[dict[str, AsyncMock]]:
"""Override async_setup and async_setup_entry.
This fixture must be declared before the hass fixture to avoid errors
in the logs during teardown of the hass fixture which calls async_unload.
"""
with patch.multiple(
"homeassistant.components.tplink",
async_setup=DEFAULT,

View File

@ -0,0 +1,146 @@
"""Constants for the tplink component tests."""
from kasa import (
DeviceConfig,
DeviceConnectionParameters,
DeviceEncryptionType,
DeviceFamily,
)
from homeassistant.components.tplink import (
CONF_AES_KEYS,
CONF_ALIAS,
CONF_CAMERA_CREDENTIALS,
CONF_CONNECTION_PARAMETERS,
CONF_CREDENTIALS_HASH,
CONF_HOST,
CONF_LIVE_VIEW,
CONF_MODEL,
CONF_USES_HTTP,
Credentials,
)
MODULE = "homeassistant.components.tplink"
MODULE_CONFIG_FLOW = "homeassistant.components.tplink.config_flow"
IP_ADDRESS = "127.0.0.1"
IP_ADDRESS2 = "127.0.0.2"
IP_ADDRESS3 = "127.0.0.3"
ALIAS = "My Bulb"
ALIAS_CAMERA = "My Camera"
MODEL = "HS100"
MODEL_CAMERA = "C210"
MAC_ADDRESS = "aa:bb:cc:dd:ee:ff"
DEVICE_ID = "123456789ABCDEFGH"
DEVICE_ID_MAC = "AA:BB:CC:DD:EE:FF"
DHCP_FORMATTED_MAC_ADDRESS = MAC_ADDRESS.replace(":", "")
MAC_ADDRESS2 = "11:22:33:44:55:66"
MAC_ADDRESS3 = "66:55:44:33:22:11"
DEFAULT_ENTRY_TITLE = f"{ALIAS} {MODEL}"
DEFAULT_ENTRY_TITLE_CAMERA = f"{ALIAS_CAMERA} {MODEL_CAMERA}"
CREDENTIALS_HASH_LEGACY = ""
CONN_PARAMS_LEGACY = DeviceConnectionParameters(
DeviceFamily.IotSmartPlugSwitch, DeviceEncryptionType.Xor
)
DEVICE_CONFIG_LEGACY = DeviceConfig(IP_ADDRESS)
DEVICE_CONFIG_DICT_LEGACY = {
k: v for k, v in DEVICE_CONFIG_LEGACY.to_dict().items() if k != "credentials"
}
CREDENTIALS = Credentials("foo", "bar")
CREDENTIALS_HASH_AES = "AES/abcdefghijklmnopqrstuvabcdefghijklmnopqrstuv=="
CREDENTIALS_HASH_KLAP = "KLAP/abcdefghijklmnopqrstuv=="
CONN_PARAMS_KLAP = DeviceConnectionParameters(
DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Klap
)
DEVICE_CONFIG_KLAP = DeviceConfig(
IP_ADDRESS,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_KLAP,
uses_http=True,
)
CONN_PARAMS_AES = DeviceConnectionParameters(
DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Aes
)
_test_privkey = (
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKLJKmBWGj6WYo9sewI8vkqar"
"Ed5H1JUr8Jj/LEWLTtV6+Mm4mfyEk6YKFHSmIG4AGgrVsGK/EbEkTZk9CwtixNQpBVc36oN2R"
"vuWWV38YnP4vI63mNxTA/gQonCsahjN4HfwE87pM7O5z39aeunoYm6Be663t33DbJH1ZUbZjm"
"tAgMBAAECgYB1Bn1KaFvRprcQOIJt51E9vNghQbf8rhj0fIEKpdC6mVhNIoUdCO+URNqnh+hP"
"SQIx4QYreUlHbsSeABFxOQSDJm6/kqyQsp59nCVDo/bXTtlvcSJ/sU3riqJNxYqEU1iJ0xMvU"
"N1VKKTmik89J8e5sN9R0AFfUSJIk7MpdOoD2QJBANTbV27nenyvbqee/ul4frdt2rrPGcGpcV"
"QmY87qbbrZgqgL5LMHHD7T/v/I8D1wRog1sBz/AiZGcnv/ox8dHKsCQQDDx8DCGPySSVqKVua"
"yUkBNpglN83wiCXZjyEtWIt+aB1A2n5ektE/o8oHnnOuvMdooxvtid7Mdapi2VLHV7VMHAkAE"
"d0GjWwnv2cJpk+VnQpbuBEkFiFjS/loZWODZM4Pv2qZqHi3DL9AA5XPBLBcWQufH7dBvG06RP"
"QMj5N4oRfUXAkEAuJJkVliqHNvM4OkGewzyFII4+WVYHNqg43dcFuuvtA27AJQ6qYtYXrvp3k"
"phI3yzOIhHTNCea1goepSkR5ODFwJBAJCTRbB+P47aEr/xA51ZFHE6VefDBJG9yg6yK4jcOxg"
"5ficXEpx8442okNtlzwa+QHpm/L3JOFrHwiEeVqXtiqY="
)
_test_pubkey = (
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiySpgVho+lmKPbHsCPL5KmqxHeR9SVK/CY"
"/yxFi07VevjJuJn8hJOmChR0piBuABoK1bBivxGxJE2ZPQsLYsTUKQVXN+qDdkb7llld/GJz+"
"LyOt5jcUwP4EKJwrGoYzeB38BPO6TOzuc9/Wnrp6GJugXuut7d9w2yR9WVG2Y5rQIDAQAB"
)
AES_KEYS = {"private": _test_privkey, "public": _test_pubkey}
DEVICE_CONFIG_AES = DeviceConfig(
IP_ADDRESS2,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_AES,
uses_http=True,
aes_keys=AES_KEYS,
)
CONN_PARAMS_AES_CAMERA = DeviceConnectionParameters(
DeviceFamily.SmartIpCamera, DeviceEncryptionType.Aes, https=True, login_version=2
)
DEVICE_CONFIG_AES_CAMERA = DeviceConfig(
IP_ADDRESS3,
credentials=CREDENTIALS,
connection_type=CONN_PARAMS_AES_CAMERA,
uses_http=True,
)
DEVICE_CONFIG_DICT_KLAP = {
k: v for k, v in DEVICE_CONFIG_KLAP.to_dict().items() if k != "credentials"
}
DEVICE_CONFIG_DICT_AES = {
k: v for k, v in DEVICE_CONFIG_AES.to_dict().items() if k != "credentials"
}
CREATE_ENTRY_DATA_LEGACY = {
CONF_HOST: IP_ADDRESS,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_LEGACY.to_dict(),
CONF_USES_HTTP: False,
}
CREATE_ENTRY_DATA_KLAP = {
CONF_HOST: IP_ADDRESS,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_KLAP,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_KLAP.to_dict(),
CONF_USES_HTTP: True,
}
CREATE_ENTRY_DATA_AES = {
CONF_HOST: IP_ADDRESS2,
CONF_ALIAS: ALIAS,
CONF_MODEL: MODEL,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES.to_dict(),
CONF_USES_HTTP: True,
CONF_AES_KEYS: AES_KEYS,
}
CREATE_ENTRY_DATA_AES_CAMERA = {
CONF_HOST: IP_ADDRESS3,
CONF_ALIAS: ALIAS_CAMERA,
CONF_MODEL: MODEL_CAMERA,
CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES,
CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES_CAMERA.to_dict(),
CONF_USES_HTTP: True,
CONF_LIVE_VIEW: True,
CONF_CAMERA_CREDENTIALS: {"username": "camuser", "password": "campass"},
}
SMALLEST_VALID_JPEG = (
"ffd8ffe000104a46494600010101004800480000ffdb00430003020202020203020202030303030406040404040408060"
"6050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b08000100"
"0101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9"
)
SMALLEST_VALID_JPEG_BYTES = bytes.fromhex(SMALLEST_VALID_JPEG)

View File

@ -4,18 +4,14 @@ from kasa import Feature
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.tplink.binary_sensor import BINARY_SENSOR_DESCRIPTIONS
from homeassistant.components.tplink.const import DOMAIN
from homeassistant.components.tplink.entity import EXCLUDED_FEATURES
from homeassistant.const import CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_feature,
_mocked_strip_children,
@ -24,6 +20,7 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry
@ -47,7 +44,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test a sensor unique ids."""
"""Test binary sensor states."""
features = {description.key for description in BINARY_SENSOR_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -68,7 +65,7 @@ async def test_binary_sensor(
entity_registry: er.EntityRegistry,
mocked_feature_binary_sensor: Feature,
) -> None:
"""Test a sensor unique ids."""
"""Test binary sensor unique ids."""
mocked_feature = mocked_feature_binary_sensor
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
@ -77,7 +74,7 @@ async def test_binary_sensor(
plug = _mocked_device(alias="my_plug", features=[mocked_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
# The entity_id is based on standard name from core.
@ -93,7 +90,7 @@ async def test_binary_sensor_children(
device_registry: dr.DeviceRegistry,
mocked_feature_binary_sensor: Feature,
) -> None:
"""Test a sensor unique ids."""
"""Test binary sensor children."""
mocked_feature = mocked_feature_binary_sensor
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
@ -105,7 +102,7 @@ async def test_binary_sensor_children(
children=_mocked_strip_children(features=[mocked_feature]),
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "binary_sensor.my_plug_overheated"

View File

@ -4,7 +4,6 @@ from kasa import Feature
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.tplink.button import BUTTON_DESCRIPTIONS
from homeassistant.components.tplink.const import DOMAIN
@ -16,11 +15,8 @@ from homeassistant.helpers import (
entity_registry as er,
issue_registry as ir,
)
from homeassistant.setup import async_setup_component
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_feature,
_mocked_strip_children,
@ -30,6 +26,7 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry
@ -83,7 +80,7 @@ def create_deprecated_child_button_entities(
@pytest.fixture
def mocked_feature_button() -> Feature:
"""Return mocked tplink binary sensor feature."""
"""Return mocked tplink button feature."""
return _mocked_feature(
"test_alarm",
value="<Action>",
@ -101,7 +98,7 @@ async def test_states(
snapshot: SnapshotAssertion,
create_deprecated_button_entities,
) -> None:
"""Test a sensor unique ids."""
"""Test button states."""
features = {description.key for description in BUTTON_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -118,14 +115,15 @@ async def test_states(
async def test_button(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
mocked_feature_button: Feature,
create_deprecated_button_entities,
) -> None:
"""Test a sensor unique ids."""
"""Test button unique ids."""
mocked_feature = mocked_feature_button
plug = _mocked_device(alias="my_device", features=[mocked_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
# The entity_id is based on standard name from core.
@ -139,11 +137,12 @@ async def test_button_children(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
mock_config_entry: MockConfigEntry,
mocked_feature_button: Feature,
create_deprecated_button_entities,
create_deprecated_child_button_entities,
) -> None:
"""Test a sensor unique ids."""
"""Test button children."""
mocked_feature = mocked_feature_button
plug = _mocked_device(
alias="my_device",
@ -151,7 +150,7 @@ async def test_button_children(
children=_mocked_strip_children(features=[mocked_feature]),
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "button.my_device_test_alarm"
@ -173,6 +172,7 @@ async def test_button_children(
async def test_button_press(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
mocked_feature_button: Feature,
create_deprecated_button_entities,
) -> None:
@ -180,7 +180,7 @@ async def test_button_press(
mocked_feature = mocked_feature_button
plug = _mocked_device(alias="my_device", features=[mocked_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "button.my_device_test_alarm"
@ -213,7 +213,7 @@ async def test_button_not_exists_with_deprecation(
mocked_feature = mocked_feature_button
dev = _mocked_device(alias="my_device", features=[mocked_feature])
with _patch_discovery(device=dev), _patch_connect(device=dev):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert not entity_registry.async_get(entity_id)
@ -265,7 +265,7 @@ async def test_button_exists_with_deprecation(
mocked_feature = mocked_feature_button
dev = _mocked_device(alias="my_device", features=[mocked_feature])
with _patch_discovery(device=dev), _patch_connect(device=dev):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity = entity_registry.async_get(entity_id)

View File

@ -11,6 +11,9 @@ from syrupy.assertion import SnapshotAssertion
from homeassistant.components import stream
from homeassistant.components.camera import (
DOMAIN as CAMERA_DOMAIN,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
CameraEntityFeature,
StreamType,
async_get_image,
@ -23,15 +26,8 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er
from . import (
DEVICE_ID,
IP_ADDRESS3,
MAC_ADDRESS3,
SMALLEST_VALID_JPEG_BYTES,
_mocked_device,
setup_platform_for_device,
snapshot_platform,
)
from . import _mocked_device, setup_platform_for_device, snapshot_platform
from .const import DEVICE_ID, IP_ADDRESS3, MAC_ADDRESS3, SMALLEST_VALID_JPEG_BYTES
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.typing import WebSocketGenerator
@ -44,7 +40,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test states."""
"""Test camera states."""
mock_camera_config_entry.add_to_hass(hass)
mock_device = _mocked_device(
@ -73,6 +69,7 @@ async def test_camera_unique_id(
hass: HomeAssistant,
mock_camera_config_entry: MockConfigEntry,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test camera unique id."""
mock_device = _mocked_device(
@ -92,14 +89,13 @@ async def test_camera_unique_id(
)
assert device_entries
entity_id = "camera.my_camera_live_view"
entity_registry = er.async_get(hass)
assert entity_registry.async_get(entity_id).unique_id == f"{DEVICE_ID}-live_view"
async def test_handle_mjpeg_stream(
hass: HomeAssistant,
mock_camera_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test handle_async_mjpeg_stream."""
mock_device = _mocked_device(
@ -126,7 +122,6 @@ async def test_handle_mjpeg_stream(
async def test_handle_mjpeg_stream_not_supported(
hass: HomeAssistant,
mock_camera_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test handle_async_mjpeg_stream."""
mock_device = _mocked_device(
@ -216,7 +211,7 @@ async def test_no_camera_image_when_streaming(
mock_camera_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test async_get_image."""
"""Test no camera image when streaming."""
mock_device = _mocked_device(
modules=[Module.Camera],
alias="my_camera",
@ -272,9 +267,8 @@ async def test_no_camera_image_when_streaming(
async def test_no_concurrent_camera_image(
hass: HomeAssistant,
mock_camera_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test async_get_image."""
"""Test async_get_image doesn't make concurrent requests."""
mock_device = _mocked_device(
modules=[Module.Camera],
alias="my_camera",
@ -321,7 +315,7 @@ async def test_camera_image_auth_error(
mock_connect: AsyncMock,
mock_discovery: AsyncMock,
) -> None:
"""Test async_get_image."""
"""Test async_get_image auth error."""
mock_device = _mocked_device(
modules=[Module.Camera],
alias="my_camera",
@ -367,7 +361,7 @@ async def test_camera_stream_source(
mock_camera_config_entry: MockConfigEntry,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test async_get_image.
"""Test camera stream source.
This test would fail if the integration didn't properly
put stream in the dependencies.
@ -444,16 +438,16 @@ async def test_camera_turn_on_off(
assert state is not None
await hass.services.async_call(
"camera",
"turn_on",
CAMERA_DOMAIN,
SERVICE_TURN_ON,
{"entity_id": "camera.my_camera_live_view"},
blocking=True,
)
mock_camera.set_state.assert_called_with(True)
await hass.services.async_call(
"camera",
"turn_off",
CAMERA_DOMAIN,
SERVICE_TURN_OFF,
{"entity_id": "camera.my_camera_live_view"},
blocking=True,
)

View File

@ -27,12 +27,12 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.util import dt as dt_util
from . import (
DEVICE_ID,
_mocked_device,
_mocked_feature,
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID
from tests.common import MockConfigEntry, async_fire_time_changed
@ -41,7 +41,7 @@ ENTITY_ID = "climate.thermostat"
@pytest.fixture
async def mocked_hub(hass: HomeAssistant) -> Device:
"""Return mocked tplink binary sensor feature."""
"""Return mocked tplink hub."""
features = [
_mocked_feature(
@ -166,7 +166,8 @@ async def test_set_hvac_mode(
)
mocked_state.set_value.assert_called_with(True)
with pytest.raises(ServiceValidationError):
msg = "Tried to set unsupported mode: dry"
with pytest.raises(ServiceValidationError, match=msg):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,

View File

@ -37,7 +37,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from . import (
from . import _mocked_device, _patch_connect, _patch_discovery, _patch_single_discovery
from .conftest import override_side_effect
from .const import (
AES_KEYS,
ALIAS,
ALIAS_CAMERA,
@ -67,12 +69,7 @@ from . import (
MODEL_CAMERA,
MODULE,
SMALLEST_VALID_JPEG_BYTES,
_mocked_device,
_patch_connect,
_patch_discovery,
_patch_single_discovery,
)
from .conftest import override_side_effect
from tests.common import MockConfigEntry
@ -168,8 +165,11 @@ async def test_discovery(
assert result2["reason"] == "no_devices_found"
@pytest.mark.usefixtures("mock_init")
async def test_discovery_camera(
hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test authenticated discovery for camera with stream."""
mock_device = _mocked_device(
@ -228,8 +228,11 @@ async def test_discovery_camera(
assert result["context"]["unique_id"] == MAC_ADDRESS3
@pytest.mark.usefixtures("mock_init")
async def test_discovery_pick_device_camera(
hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test authenticated discovery for camera with stream."""
mock_device = _mocked_device(
@ -293,8 +296,11 @@ async def test_discovery_pick_device_camera(
assert result["context"]["unique_id"] == MAC_ADDRESS3
@pytest.mark.usefixtures("mock_init")
async def test_discovery_auth(
hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test authenticated discovery."""
mock_device = _mocked_device(
@ -336,8 +342,11 @@ async def test_discovery_auth(
assert result2["context"]["unique_id"] == MAC_ADDRESS
@pytest.mark.usefixtures("mock_init")
async def test_discovery_auth_camera(
hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test authenticated discovery for camera with stream."""
mock_device = _mocked_device(
@ -407,13 +416,13 @@ async def test_discovery_auth_camera(
],
ids=["invalid-auth", "unknown-error"],
)
@pytest.mark.usefixtures("mock_init")
async def test_discovery_auth_errors(
hass: HomeAssistant,
mock_connect: AsyncMock,
mock_init,
error_type,
errors_msg,
error_placement,
error_type: Exception,
errors_msg: str,
error_placement: str,
) -> None:
"""Test handling of discovery authentication errors.
@ -465,10 +474,10 @@ async def test_discovery_auth_errors(
assert result3["context"]["unique_id"] == MAC_ADDRESS
@pytest.mark.usefixtures("mock_init")
async def test_discovery_new_credentials(
hass: HomeAssistant,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test setting up discovery with new credentials."""
mock_device = mock_connect["mock_devices"][IP_ADDRESS]
@ -514,10 +523,10 @@ async def test_discovery_new_credentials(
assert result3["context"]["unique_id"] == MAC_ADDRESS
@pytest.mark.usefixtures("mock_init")
async def test_discovery_new_credentials_invalid(
hass: HomeAssistant,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test setting up discovery with new invalid credentials."""
mock_device = mock_connect["mock_devices"][IP_ADDRESS]
@ -977,11 +986,11 @@ async def test_manual_no_capabilities(hass: HomeAssistant) -> None:
assert result["context"]["unique_id"] == MAC_ADDRESS
@pytest.mark.usefixtures("mock_init")
async def test_manual_auth(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test manually setup."""
result = await hass.config_entries.flow.async_init(
@ -1083,14 +1092,14 @@ async def test_manual_auth_camera(
],
ids=["invalid-auth", "unknown-error"],
)
@pytest.mark.usefixtures("mock_init")
async def test_manual_auth_errors(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
mock_init,
error_type,
errors_msg,
error_placement,
error_type: Exception,
errors_msg: str,
error_placement: str,
) -> None:
"""Test manually setup auth errors."""
result = await hass.config_entries.flow.async_init(
@ -1150,9 +1159,9 @@ async def test_manual_port_override(
hass: HomeAssistant,
mock_connect: AsyncMock,
mock_discovery: AsyncMock,
host_str,
host,
port,
host_str: str,
host: str,
port: int,
) -> None:
"""Test manually setup."""
config = DeviceConfig(
@ -1342,7 +1351,7 @@ async def test_discovered_by_discovery_and_dhcp(hass: HomeAssistant) -> None:
],
)
async def test_discovered_by_dhcp_or_discovery(
hass: HomeAssistant, source, data
hass: HomeAssistant, source: str, data: dict
) -> None:
"""Test we can setup when discovered from dhcp or discovery."""
@ -1396,7 +1405,7 @@ async def test_discovered_by_dhcp_or_discovery(
],
)
async def test_discovered_by_dhcp_or_discovery_failed_to_get_device(
hass: HomeAssistant, source, data
hass: HomeAssistant, source: str, data: dict
) -> None:
"""Test we abort if we cannot get the unique id when discovered from dhcp."""
@ -1419,7 +1428,7 @@ async def test_integration_discovery_with_ip_change(
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test reauth flow."""
"""Test integration updates ip address from discovery."""
mock_config_entry.add_to_hass(hass)
with (
patch("homeassistant.components.tplink.Discover.discover", return_value={}),
@ -1670,7 +1679,7 @@ async def test_reauth_camera(
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
) -> None:
"""Test async_get_image."""
"""Test reauth flow on invalid camera credentials."""
mock_device = mock_connect["mock_devices"][IP_ADDRESS3]
mock_camera_config_entry.add_to_hass(hass)
mock_camera_config_entry.async_start_reauth(
@ -1762,7 +1771,7 @@ async def test_reauth_try_connect_all_fail(
override_side_effect(mock_discovery["discover_single"], TimeoutError),
override_side_effect(mock_discovery["try_connect_all"], lambda *_, **__: None),
):
result2 = await hass.config_entries.flow.async_configure(
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: "fake_username",
@ -1774,7 +1783,23 @@ async def test_reauth_try_connect_all_fail(
IP_ADDRESS, credentials=credentials, port=None
)
mock_discovery["try_connect_all"].assert_called_once()
assert result2["errors"] == {"base": "cannot_connect"}
assert result["errors"] == {"base": "cannot_connect"}
mock_discovery["try_connect_all"].reset_mock()
with (
override_side_effect(mock_discovery["discover_single"], TimeoutError),
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: "fake_username",
CONF_PASSWORD: "fake_password",
},
)
mock_discovery["try_connect_all"].assert_called_once()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
async def test_reauth_update_with_encryption_change(
@ -2025,9 +2050,9 @@ async def test_reauth_errors(
mock_added_config_entry: MockConfigEntry,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
error_type,
errors_msg,
error_placement,
error_type: Exception,
errors_msg: str,
error_placement: str,
) -> None:
"""Test reauth errors."""
mock_added_config_entry.async_start_reauth(hass)
@ -2089,8 +2114,8 @@ async def test_pick_device_errors(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
error_type,
expected_flow,
error_type: type[Exception],
expected_flow: FlowResultType,
) -> None:
"""Test errors on pick_device."""
result = await hass.config_entries.flow.async_init(
@ -2127,11 +2152,11 @@ async def test_pick_device_errors(
assert result4["context"]["unique_id"] == MAC_ADDRESS
@pytest.mark.usefixtures("mock_init")
async def test_discovery_timeout_try_connect_all(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test discovery tries legacy connect on timeout."""
result = await hass.config_entries.flow.async_init(
@ -2153,11 +2178,11 @@ async def test_discovery_timeout_try_connect_all(
assert mock_connect["connect"].call_count == 1
@pytest.mark.usefixtures("mock_init")
async def test_discovery_timeout_try_connect_all_needs_creds(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test discovery tries legacy connect on timeout."""
result = await hass.config_entries.flow.async_init(
@ -2191,11 +2216,11 @@ async def test_discovery_timeout_try_connect_all_needs_creds(
assert mock_connect["connect"].call_count == 1
@pytest.mark.usefixtures("mock_init")
async def test_discovery_timeout_try_connect_all_fail(
hass: HomeAssistant,
mock_discovery: AsyncMock,
mock_connect: AsyncMock,
mock_init,
) -> None:
"""Test discovery tries legacy connect on timeout."""
result = await hass.config_entries.flow.async_init(

View File

@ -2,8 +2,7 @@
from __future__ import annotations
from datetime import timedelta
from freezegun.api import FrozenDateTimeFactory
from kasa import Device, Module
from syrupy.assertion import SnapshotAssertion
@ -11,13 +10,15 @@ from homeassistant.components.fan import (
ATTR_PERCENTAGE,
DOMAIN as FAN_DOMAIN,
SERVICE_SET_PERCENTAGE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
import homeassistant.util.dt as dt_util
from . import DEVICE_ID, _mocked_device, setup_platform_for_device, snapshot_platform
from . import _mocked_device, setup_platform_for_device, snapshot_platform
from .const import DEVICE_ID
from tests.common import MockConfigEntry, async_fire_time_changed
@ -56,6 +57,7 @@ async def test_fan_unique_id(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test a fan unique id."""
fan = _mocked_device(modules=[Module.Fan], alias="my_fan")
@ -66,12 +68,16 @@ async def test_fan_unique_id(
)
assert device_entries
entity_id = "fan.my_fan"
entity_registry = er.async_get(hass)
assert entity_registry.async_get(entity_id).unique_id == DEVICE_ID
async def test_fan(hass: HomeAssistant, mock_config_entry: MockConfigEntry) -> None:
"""Test a color fan and that all transitions are correctly passed."""
async def test_fan(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test fan functionality."""
device = _mocked_device(modules=[Module.Fan], alias="my_fan")
fan = device.modules[Module.Fan]
fan.fan_speed_level = 0
@ -83,26 +89,29 @@ async def test_fan(hass: HomeAssistant, mock_config_entry: MockConfigEntry) -> N
assert state.state == "off"
await hass.services.async_call(
FAN_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
FAN_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
fan.set_fan_speed_level.assert_called_once_with(4)
fan.set_fan_speed_level.reset_mock()
fan.fan_speed_level = 4
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
freezer.tick(10)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id)
assert state.state == "on"
await hass.services.async_call(
FAN_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
FAN_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
fan.set_fan_speed_level.assert_called_once_with(0)
fan.set_fan_speed_level.reset_mock()
await hass.services.async_call(
FAN_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_PERCENTAGE: 50},
blocking=True,
)

View File

@ -38,6 +38,14 @@ from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from . import (
_mocked_device,
_mocked_feature,
_patch_connect,
_patch_discovery,
_patch_single_discovery,
)
from .conftest import override_side_effect
from .const import (
ALIAS,
CREATE_ENTRY_DATA_AES,
CREATE_ENTRY_DATA_KLAP,
@ -53,13 +61,7 @@ from . import (
IP_ADDRESS,
MAC_ADDRESS,
MODEL,
_mocked_device,
_mocked_feature,
_patch_connect,
_patch_discovery,
_patch_single_discovery,
)
from .conftest import override_side_effect
from tests.common import MockConfigEntry, async_fire_time_changed
@ -98,7 +100,7 @@ async def test_config_entry_reload(hass: HomeAssistant) -> None:
)
already_migrated_config_entry.add_to_hass(hass)
with _patch_discovery(), _patch_single_discovery(), _patch_connect():
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
assert already_migrated_config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(already_migrated_config_entry.entry_id)
@ -117,7 +119,7 @@ async def test_config_entry_retry(hass: HomeAssistant) -> None:
_patch_single_discovery(no_device=True),
_patch_connect(no_device=True),
):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY
@ -175,7 +177,7 @@ async def test_config_entry_wrong_mac_Address(
)
already_migrated_config_entry.add_to_hass(hass)
with _patch_discovery(), _patch_single_discovery(), _patch_connect():
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY
@ -309,7 +311,7 @@ async def test_plug_auth_fails(hass: HomeAssistant) -> None:
config_entry.add_to_hass(hass)
device = _mocked_device(alias="my_plug", features=["state"])
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug"
@ -355,7 +357,7 @@ async def test_update_attrs_fails_in_init(
type(light_module).color_temp = p
light.__str__ = lambda _: "MockLight"
with _patch_discovery(device=light), _patch_connect(device=light):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -388,7 +390,7 @@ async def test_update_attrs_fails_on_update(
light_module = light.modules[Module.Light]
with _patch_discovery(device=light), _patch_connect(device=light):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -434,7 +436,7 @@ async def test_feature_no_category(
)
dev.features["led"].category = Feature.Category.Unset
with _patch_discovery(device=dev), _patch_connect(device=dev):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug_led"

View File

@ -20,6 +20,11 @@ from kasa.iot import IotDevice
import pytest
from homeassistant.components import tplink
from homeassistant.components.homeassistant.scene import (
CONF_SCENE_ID,
CONF_SNAPSHOT,
SERVICE_CREATE,
)
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_MODE,
@ -35,7 +40,10 @@ from homeassistant.components.light import (
ATTR_XY_COLOR,
DOMAIN as LIGHT_DOMAIN,
EFFECT_OFF,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN
from homeassistant.components.tplink.const import DOMAIN
from homeassistant.components.tplink.light import (
SERVICE_RANDOM_EFFECT,
@ -56,14 +64,13 @@ from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_feature,
_patch_connect,
_patch_discovery,
_patch_single_discovery,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry, async_fire_time_changed
@ -88,7 +95,7 @@ async def test_light_unique_id(
light = _mocked_device(modules=[Module.Light], alias="my_light")
light.device_type = device_type
with _patch_discovery(device=light), _patch_connect(device=light):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -98,8 +105,11 @@ async def test_light_unique_id(
)
async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None:
"""Test a light unique id."""
async def test_legacy_dimmer_unique_id(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Test dimmer unique id."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -113,16 +123,16 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None:
light.device_type = DeviceType.Dimmer
with _patch_discovery(device=light), _patch_connect(device=light):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
entity_registry = er.async_get(hass)
assert entity_registry.async_get(entity_id).unique_id == "aa:bb:cc:dd:ee:ff"
@pytest.mark.parametrize(
("device", "transition"),
("device", "extra_data", "expected_transition"),
[
(
_mocked_device(
@ -135,7 +145,138 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None:
),
],
),
2.0,
{ATTR_TRANSITION: 2.0},
2.0 * 1_000,
),
(
_mocked_device(
modules=[Module.Light],
features=[
_mocked_feature("brightness", value=50),
_mocked_feature("hsv", value=(10, 30, 5)),
_mocked_feature(
"color_temp", value=4000, minimum_value=4000, maximum_value=9000
),
],
),
{},
None,
),
],
)
async def test_color_light(
hass: HomeAssistant,
device: MagicMock,
extra_data: dict,
expected_transition: float | None,
) -> None:
"""Test a color light and that all transitions are correctly passed."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
already_migrated_config_entry.add_to_hass(hass)
light = device.modules[Module.Light]
# Setting color_temp to None emulates a device without color temp
light.color_temp = None
with _patch_discovery(device=device), _patch_connect(device=device):
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_bulb"
BASE_PAYLOAD = {ATTR_ENTITY_ID: entity_id}
BASE_PAYLOAD |= extra_data
state = hass.states.get(entity_id)
assert state.state == "on"
attributes = state.attributes
assert attributes[ATTR_BRIGHTNESS] == 128
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"]
assert attributes.get(ATTR_EFFECT) is None
assert attributes[ATTR_COLOR_MODE] == "hs"
assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000
assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000
assert attributes[ATTR_HS_COLOR] == (10, 30)
assert attributes[ATTR_RGB_COLOR] == (255, 191, 178)
assert attributes[ATTR_XY_COLOR] == (0.42, 0.336)
await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_OFF, BASE_PAYLOAD, blocking=True
)
light.set_state.assert_called_once_with(
LightState(light_on=False, transition=expected_transition)
)
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_ON, BASE_PAYLOAD, blocking=True
)
light.set_state.assert_called_once_with(
LightState(light_on=True, transition=expected_transition)
)
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_BRIGHTNESS: 100},
blocking=True,
)
light.set_brightness.assert_called_with(39, transition=expected_transition)
light.set_brightness.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
light.set_color_temp.assert_called_with(
6666, brightness=None, transition=expected_transition
)
light.set_color_temp.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
light.set_color_temp.assert_called_with(
6666, brightness=None, transition=expected_transition
)
light.set_color_temp.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_HS_COLOR: (10, 30)},
blocking=True,
)
light.set_hsv.assert_called_with(10, 30, None, transition=expected_transition)
light.set_hsv.reset_mock()
@pytest.mark.parametrize(
("device", "extra_data", "expected_transition"),
[
(
_mocked_device(
modules=[Module.Light, Module.LightEffect],
features=[
_mocked_feature("brightness", value=50),
_mocked_feature("hsv", value=(10, 30, 5)),
_mocked_feature(
"color_temp", value=4000, minimum_value=4000, maximum_value=9000
),
],
),
{ATTR_TRANSITION: 2.0},
2.0 * 1_000,
),
(
_mocked_device(
@ -148,12 +289,16 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None:
),
],
),
{},
None,
),
],
)
async def test_color_light(
hass: HomeAssistant, device: MagicMock, transition: float | None
async def test_color_light_with_active_effect(
hass: HomeAssistant,
device: MagicMock,
extra_data: dict,
expected_transition: float | None,
) -> None:
"""Test a color light and that all transitions are correctly passed."""
already_migrated_config_entry = MockConfigEntry(
@ -162,93 +307,84 @@ async def test_color_light(
already_migrated_config_entry.add_to_hass(hass)
light = device.modules[Module.Light]
# Setting color_temp to None emulates a device with active effects
light.color_temp = None
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_bulb"
KASA_TRANSITION_VALUE = transition * 1_000 if transition is not None else None
BASE_PAYLOAD = {ATTR_ENTITY_ID: entity_id}
if transition:
BASE_PAYLOAD[ATTR_TRANSITION] = transition
BASE_PAYLOAD |= extra_data
state = hass.states.get(entity_id)
assert state.state == "on"
attributes = state.attributes
assert attributes[ATTR_BRIGHTNESS] == 128
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"]
# If effect is active, only the brightness can be controlled
if attributes.get(ATTR_EFFECT) is not None:
assert attributes.get(ATTR_EFFECT) is not None
assert attributes[ATTR_COLOR_MODE] == "brightness"
else:
assert attributes[ATTR_COLOR_MODE] == "hs"
assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000
assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000
assert attributes[ATTR_HS_COLOR] == (10, 30)
assert attributes[ATTR_RGB_COLOR] == (255, 191, 178)
assert attributes[ATTR_XY_COLOR] == (0.42, 0.336)
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", BASE_PAYLOAD, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, BASE_PAYLOAD, blocking=True
)
light.set_state.assert_called_once_with(
LightState(light_on=False, transition=KASA_TRANSITION_VALUE)
LightState(light_on=False, transition=expected_transition)
)
light.set_state.reset_mock()
await hass.services.async_call(LIGHT_DOMAIN, "turn_on", BASE_PAYLOAD, blocking=True)
await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_ON, BASE_PAYLOAD, blocking=True
)
light.set_state.assert_called_once_with(
LightState(light_on=True, transition=KASA_TRANSITION_VALUE)
LightState(light_on=True, transition=expected_transition)
)
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_BRIGHTNESS: 100},
blocking=True,
)
light.set_brightness.assert_called_with(39, transition=KASA_TRANSITION_VALUE)
light.set_brightness.assert_called_with(39, transition=expected_transition)
light.set_brightness.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
light.set_color_temp.assert_called_with(
6666, brightness=None, transition=KASA_TRANSITION_VALUE
6666, brightness=None, transition=expected_transition
)
light.set_color_temp.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
light.set_color_temp.assert_called_with(
6666, brightness=None, transition=KASA_TRANSITION_VALUE
6666, brightness=None, transition=expected_transition
)
light.set_color_temp.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{**BASE_PAYLOAD, ATTR_HS_COLOR: (10, 30)},
blocking=True,
)
light.set_hsv.assert_called_with(10, 30, None, transition=KASA_TRANSITION_VALUE)
light.set_hsv.assert_called_with(10, 30, None, transition=expected_transition)
light.set_hsv.reset_mock()
async def test_color_light_no_temp(hass: HomeAssistant) -> None:
"""Test a light."""
"""Test a color light with no color temp."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -263,7 +399,7 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None:
type(light).color_temp = PropertyMock(side_effect=Exception)
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -279,20 +415,20 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None:
assert attributes[ATTR_XY_COLOR] == (0.42, 0.336)
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
blocking=True,
)
@ -301,7 +437,7 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None:
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_HS_COLOR: (10, 30)},
blocking=True,
)
@ -309,11 +445,9 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None:
light.set_hsv.reset_mock()
@pytest.mark.parametrize(
("device", "is_color"),
[
(
_mocked_device(
async def test_color_temp_light_color(hass: HomeAssistant) -> None:
"""Test a color temp light with color."""
device = _mocked_device(
modules=[Module.Light],
alias="my_light",
features=[
@ -323,37 +457,16 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None:
"color_temp", value=4000, minimum_value=4000, maximum_value=9000
),
],
),
True,
),
(
_mocked_device(
modules=[Module.Light],
alias="my_light",
features=[
_mocked_feature("brightness", value=50),
_mocked_feature(
"color_temp", value=4000, minimum_value=4000, maximum_value=9000
),
],
),
False,
),
],
)
async def test_color_temp_light(
hass: HomeAssistant, device: MagicMock, is_color: bool
) -> None:
"""Test a light."""
)
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
already_migrated_config_entry.add_to_hass(hass)
# device = _mocked_device(modules=[Module.Light], alias="my_light")
light = device.modules[Module.Light]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -363,29 +476,24 @@ async def test_color_temp_light(
attributes = state.attributes
assert attributes[ATTR_BRIGHTNESS] == 128
assert attributes[ATTR_COLOR_MODE] == "color_temp"
if is_color:
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"]
else:
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp"]
assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000
assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000
assert attributes[ATTR_COLOR_TEMP_KELVIN] == 4000
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
blocking=True,
)
@ -394,7 +502,7 @@ async def test_color_temp_light(
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
@ -404,7 +512,7 @@ async def test_color_temp_light(
# Verify color temp is clamped to the valid range
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 20000},
blocking=True,
)
@ -414,7 +522,94 @@ async def test_color_temp_light(
# Verify color temp is clamped to the valid range
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 1},
blocking=True,
)
light.set_color_temp.assert_called_with(4000, brightness=None, transition=None)
light.set_color_temp.reset_mock()
async def test_color_temp_light_no_color(hass: HomeAssistant) -> None:
"""Test a color temp light with no color."""
device = _mocked_device(
modules=[Module.Light],
alias="my_light",
features=[
_mocked_feature("brightness", value=50),
_mocked_feature(
"color_temp", value=4000, minimum_value=4000, maximum_value=9000
),
],
)
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
already_migrated_config_entry.add_to_hass(hass)
light = device.modules[Module.Light]
with _patch_discovery(device=device), _patch_connect(device=device):
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
state = hass.states.get(entity_id)
assert state.state == "on"
attributes = state.attributes
assert attributes[ATTR_BRIGHTNESS] == 128
assert attributes[ATTR_COLOR_MODE] == "color_temp"
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp"]
assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000
assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000
assert attributes[ATTR_COLOR_TEMP_KELVIN] == 4000
await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
blocking=True,
)
light.set_brightness.assert_called_with(39, transition=None)
light.set_brightness.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 6666},
blocking=True,
)
light.set_color_temp.assert_called_with(6666, brightness=None, transition=None)
light.set_color_temp.reset_mock()
# Verify color temp is clamped to the valid range
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 20000},
blocking=True,
)
light.set_color_temp.assert_called_with(9000, brightness=None, transition=None)
light.set_color_temp.reset_mock()
# Verify color temp is clamped to the valid range
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 1},
blocking=True,
)
@ -423,7 +618,7 @@ async def test_color_temp_light(
async def test_brightness_only_light(hass: HomeAssistant) -> None:
"""Test a light."""
"""Test a light brightness."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -435,7 +630,7 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None:
light = device.modules[Module.Light]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -448,20 +643,20 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None:
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["brightness"]
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
blocking=True,
)
@ -470,7 +665,7 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None:
async def test_on_off_light(hass: HomeAssistant) -> None:
"""Test a light."""
"""Test a light turns on and off."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -479,7 +674,7 @@ async def test_on_off_light(hass: HomeAssistant) -> None:
light = device.modules[Module.Light]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -490,20 +685,20 @@ async def test_on_off_light(hass: HomeAssistant) -> None:
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["onoff"]
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once()
light.set_state.reset_mock()
async def test_off_at_start_light(hass: HomeAssistant) -> None:
"""Test a light."""
"""Test a light off at startup."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -514,7 +709,7 @@ async def test_off_at_start_light(hass: HomeAssistant) -> None:
light.state = LightState(light_on=False)
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -526,7 +721,7 @@ async def test_off_at_start_light(hass: HomeAssistant) -> None:
async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None:
"""Test a light."""
"""Test a dimmer turns on without brightness being set."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -537,7 +732,7 @@ async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None:
light.state = LightState(light_on=False)
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -546,7 +741,7 @@ async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None:
assert state.state == "off"
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
light.set_state.assert_called_once_with(
LightState(
@ -587,7 +782,7 @@ async def test_smart_strip_effects(
_patch_single_discovery(device=device),
_patch_connect(device=device),
):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -601,7 +796,7 @@ async def test_smart_strip_effects(
# is in progress calls set_effect to clear the effect
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 4000},
blocking=True,
)
@ -612,7 +807,7 @@ async def test_smart_strip_effects(
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "Effect2"},
blocking=True,
)
@ -629,7 +824,7 @@ async def test_smart_strip_effects(
# Test setting light effect off
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "off"},
blocking=True,
)
@ -644,7 +839,7 @@ async def test_smart_strip_effects(
caplog.clear()
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "Effect3"},
blocking=True,
)
@ -673,7 +868,7 @@ async def test_smart_strip_effects(
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
@ -703,7 +898,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
light_effect = device.modules[Module.LightEffect]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -713,7 +908,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
await hass.services.async_call(
DOMAIN,
"random_effect",
SERVICE_RANDOM_EFFECT,
{
ATTR_ENTITY_ID: entity_id,
"init_states": [340, 20, 50],
@ -742,7 +937,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
await hass.services.async_call(
DOMAIN,
"random_effect",
SERVICE_RANDOM_EFFECT,
{
ATTR_ENTITY_ID: entity_id,
"init_states": [340, 20, 50],
@ -792,7 +987,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
@ -801,7 +996,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
await hass.services.async_call(
DOMAIN,
"random_effect",
SERVICE_RANDOM_EFFECT,
{
ATTR_ENTITY_ID: entity_id,
"init_states": [340, 20, 50],
@ -875,7 +1070,7 @@ async def test_smart_strip_effect_service_error(
service_params: dict,
expected_extra_params: dict,
) -> None:
"""Test smart strip custom random effects."""
"""Test smart strip effect service errors."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -886,7 +1081,7 @@ async def test_smart_strip_effect_service_error(
light_effect = device.modules[Module.LightEffect]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -935,7 +1130,7 @@ async def test_smart_strip_custom_random_effect_at_start(hass: HomeAssistant) ->
light_effect = device.modules[Module.LightEffect]
light_effect.effect = LightEffect.LIGHT_EFFECTS_OFF
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -945,7 +1140,7 @@ async def test_smart_strip_custom_random_effect_at_start(hass: HomeAssistant) ->
# fallback to set HSV when custom effect is not known so it does turn back on
await hass.services.async_call(
LIGHT_DOMAIN,
"turn_on",
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
@ -965,7 +1160,7 @@ async def test_smart_strip_custom_sequence_effect(hass: HomeAssistant) -> None:
light_effect = device.modules[Module.LightEffect]
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -975,7 +1170,7 @@ async def test_smart_strip_custom_sequence_effect(hass: HomeAssistant) -> None:
await hass.services.async_call(
DOMAIN,
"sequence_effect",
SERVICE_SEQUENCE_EFFECT,
{
ATTR_ENTITY_ID: entity_id,
"sequence": [[340, 20, 50], [20, 50, 50], [0, 100, 50]],
@ -1040,7 +1235,7 @@ async def test_light_errors_when_turned_on(
light.set_state.side_effect = exception_type(msg)
with _patch_discovery(device=device), _patch_connect(device=device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_light"
@ -1051,7 +1246,7 @@ async def test_light_errors_when_turned_on(
with pytest.raises(HomeAssistantError, match=msg):
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
await hass.async_block_till_done()
assert light.set_state.call_count == 1
@ -1091,7 +1286,7 @@ async def test_light_child(
)
with _patch_discovery(device=parent_device), _patch_connect(device=parent_device):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "light.my_device"
@ -1132,14 +1327,16 @@ async def test_scene_effect_light(
light_effect.effect = LightEffect.LIGHT_EFFECTS_OFF
with _patch_discovery(device=device), _patch_connect(device=device):
assert await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
assert await async_setup_component(hass, "scene", {})
assert await hass.config_entries.async_setup(
already_migrated_config_entry.entry_id
)
assert await async_setup_component(hass, SCENE_DOMAIN, {})
await hass.async_block_till_done()
entity_id = "light.my_light"
await hass.services.async_call(
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
await hass.async_block_till_done()
freezer.tick(5)
@ -1151,9 +1348,9 @@ async def test_scene_effect_light(
assert state.attributes["effect"] is EFFECT_OFF
await hass.services.async_call(
"scene",
"create",
{"scene_id": "effect_off_scene", "snapshot_entities": [entity_id]},
SCENE_DOMAIN,
SERVICE_CREATE,
{CONF_SCENE_ID: "effect_off_scene", CONF_SNAPSHOT: [entity_id]},
blocking=True,
)
await hass.async_block_till_done()
@ -1161,7 +1358,7 @@ async def test_scene_effect_light(
assert scene_state.state is STATE_UNKNOWN
await hass.services.async_call(
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
await hass.async_block_till_done()
freezer.tick(5)
@ -1172,10 +1369,10 @@ async def test_scene_effect_light(
assert state.state is STATE_OFF
await hass.services.async_call(
"scene",
"turn_on",
SCENE_DOMAIN,
SERVICE_TURN_ON,
{
"entity_id": "scene.effect_off_scene",
ATTR_ENTITY_ID: "scene.effect_off_scene",
},
blocking=True,
)

View File

@ -3,7 +3,6 @@
from kasa import Feature
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.number import (
ATTR_VALUE,
DOMAIN as NUMBER_DOMAIN,
@ -15,11 +14,8 @@ from homeassistant.components.tplink.number import NUMBER_DESCRIPTIONS
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_feature,
_mocked_strip_children,
@ -28,6 +24,7 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry
@ -39,7 +36,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test a sensor unique ids."""
"""Test a number states."""
features = {description.key for description in NUMBER_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -54,7 +51,7 @@ async def test_states(
async def test_number(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None:
"""Test a sensor unique ids."""
"""Test number unique ids."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -70,7 +67,7 @@ async def test_number(hass: HomeAssistant, entity_registry: er.EntityRegistry) -
)
plug = _mocked_device(alias="my_plug", features=[new_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "number.my_plug_temperature_offset"
@ -84,7 +81,7 @@ async def test_number_children(
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test a sensor unique ids."""
"""Test number children."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -104,7 +101,7 @@ async def test_number_children(
children=_mocked_strip_children(features=[new_feature]),
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "number.my_plug_temperature_offset"
@ -142,7 +139,7 @@ async def test_number_set(
)
plug = _mocked_device(alias="my_plug", features=[new_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "number.my_plug_temperature_offset"

View File

@ -4,7 +4,6 @@ from kasa import Feature
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.select import (
ATTR_OPTION,
DOMAIN as SELECT_DOMAIN,
@ -16,11 +15,8 @@ from homeassistant.components.tplink.select import SELECT_DESCRIPTIONS
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_feature,
_mocked_strip_children,
@ -29,13 +25,14 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry
@pytest.fixture
def mocked_feature_select() -> Feature:
"""Return mocked tplink binary sensor feature."""
"""Return mocked tplink select feature."""
return _mocked_feature(
"light_preset",
value="First choice",
@ -53,7 +50,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test a sensor unique ids."""
"""Test select states."""
features = {description.key for description in SELECT_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -72,7 +69,7 @@ async def test_select(
entity_registry: er.EntityRegistry,
mocked_feature_select: Feature,
) -> None:
"""Test a sensor unique ids."""
"""Test select unique ids."""
mocked_feature = mocked_feature_select
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
@ -81,7 +78,7 @@ async def test_select(
plug = _mocked_device(alias="my_plug", features=[mocked_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
# The entity_id is based on standard name from core.
@ -97,7 +94,7 @@ async def test_select_children(
device_registry: dr.DeviceRegistry,
mocked_feature_select: Feature,
) -> None:
"""Test a sensor unique ids."""
"""Test select children."""
mocked_feature = mocked_feature_select
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
@ -109,7 +106,7 @@ async def test_select_children(
children=_mocked_strip_children(features=[mocked_feature]),
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "select.my_plug_light_preset"
@ -141,7 +138,7 @@ async def test_select_select(
already_migrated_config_entry.add_to_hass(hass)
plug = _mocked_device(alias="my_plug", features=[mocked_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "select.my_plug_light_preset"

View File

@ -4,18 +4,14 @@ from kasa import Device, Feature, Module
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.tplink.const import DOMAIN
from homeassistant.components.tplink.entity import EXCLUDED_FEATURES
from homeassistant.components.tplink.sensor import SENSOR_DESCRIPTIONS
from homeassistant.const import CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_energy_features,
_mocked_feature,
@ -25,6 +21,7 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry
@ -36,7 +33,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test a sensor unique ids."""
"""Test a sensor states."""
features = {description.key for description in SENSOR_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -67,7 +64,7 @@ async def test_color_light_with_an_emeter(hass: HomeAssistant) -> None:
alias="my_bulb", modules=[Module.Light], features=["state", *emeter_features]
)
with _patch_discovery(device=bulb), _patch_connect(device=bulb):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
@ -104,7 +101,7 @@ async def test_plug_with_an_emeter(hass: HomeAssistant) -> None:
)
plug = _mocked_device(alias="my_plug", features=["state", *emeter_features])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
@ -131,7 +128,7 @@ async def test_color_light_no_emeter(hass: HomeAssistant) -> None:
bulb = _mocked_device(alias="my_bulb", modules=[Module.Light])
with _patch_discovery(device=bulb), _patch_connect(device=bulb):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
@ -167,7 +164,7 @@ async def test_sensor_unique_id(
)
plug = _mocked_device(alias="my_plug", features=emeter_features)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
expected = {
@ -202,7 +199,7 @@ async def test_undefined_sensor(
)
plug = _mocked_device(alias="my_plug", features=[new_feature])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
msg = (
@ -240,7 +237,7 @@ async def test_sensor_children_on_parent(
device_type=Device.Type.WallSwitch,
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "sensor.my_plug_this_month_s_consumption"
@ -288,7 +285,7 @@ async def test_sensor_children_on_child(
device_type=Device.Type.Strip,
)
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "sensor.my_plug_this_month_s_consumption"
@ -308,19 +305,18 @@ async def test_sensor_children_on_child(
assert child_device.via_device_id == device.id
@pytest.mark.skip
async def test_new_datetime_sensor(
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_datetime_sensor(
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test a sensor unique ids."""
# Skipped temporarily while datetime handling on hold.
"""Test a timestamp sensor."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
already_migrated_config_entry.add_to_hass(hass)
plug = _mocked_device(alias="my_plug", features=["on_since"])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "sensor.my_plug_on_since"

View File

@ -9,7 +9,11 @@ import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import tplink
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.switch import (
DOMAIN as SWITCH_DOMAIN,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.components.tplink.const import DOMAIN
from homeassistant.components.tplink.entity import EXCLUDED_FEATURES
from homeassistant.components.tplink.switch import SWITCH_DESCRIPTIONS
@ -25,12 +29,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util, slugify
from . import (
DEVICE_ID,
MAC_ADDRESS,
_mocked_device,
_mocked_strip_children,
_patch_connect,
@ -38,6 +39,7 @@ from . import (
setup_platform_for_device,
snapshot_platform,
)
from .const import DEVICE_ID, MAC_ADDRESS
from tests.common import MockConfigEntry, async_fire_time_changed
@ -49,7 +51,7 @@ async def test_states(
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test a sensor unique ids."""
"""Test a switch states."""
features = {description.key for description in SWITCH_DESCRIPTIONS}
features.update(EXCLUDED_FEATURES)
device = _mocked_device(alias="my_device", features=features)
@ -72,7 +74,7 @@ async def test_plug(hass: HomeAssistant) -> None:
plug = _mocked_device(alias="my_plug", features=["state"])
feat = plug.features["state"]
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug"
@ -80,13 +82,13 @@ async def test_plug(hass: HomeAssistant) -> None:
assert state.state == STATE_ON
await hass.services.async_call(
SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
await hass.services.async_call(
SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
@ -120,7 +122,7 @@ async def test_led_switch(hass: HomeAssistant, dev: Device, domain: str) -> None
feat = dev.features["led"]
already_migrated_config_entry.add_to_hass(hass)
with _patch_discovery(device=dev), _patch_connect(device=dev):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_name = slugify(dev.alias)
@ -131,13 +133,13 @@ async def test_led_switch(hass: HomeAssistant, dev: Device, domain: str) -> None
assert led_state.name == f"{dev.alias} LED"
await hass.services.async_call(
SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: led_entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: led_entity_id}, blocking=True
)
feat.set_value.assert_called_once_with(False)
feat.set_value.reset_mock()
await hass.services.async_call(
SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: led_entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: led_entity_id}, blocking=True
)
feat.set_value.assert_called_once_with(True)
feat.set_value.reset_mock()
@ -153,7 +155,7 @@ async def test_plug_unique_id(
already_migrated_config_entry.add_to_hass(hass)
plug = _mocked_device(alias="my_plug", features=["state", "led"])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug"
@ -168,7 +170,7 @@ async def test_plug_update_fails(hass: HomeAssistant) -> None:
already_migrated_config_entry.add_to_hass(hass)
plug = _mocked_device(alias="my_plug", features=["state", "led"])
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug"
@ -197,7 +199,7 @@ async def test_strip(hass: HomeAssistant) -> None:
strip.children[0].features["state"].value = True
strip.children[1].features["state"].value = False
with _patch_discovery(device=strip), _patch_connect(device=strip):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_strip_plug0"
@ -205,14 +207,14 @@ async def test_strip(hass: HomeAssistant) -> None:
assert state.state == STATE_ON
await hass.services.async_call(
SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat = strip.children[0].features["state"]
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
await hass.services.async_call(
SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
@ -222,14 +224,14 @@ async def test_strip(hass: HomeAssistant) -> None:
assert state.state == STATE_OFF
await hass.services.async_call(
SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat = strip.children[1].features["state"]
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
await hass.services.async_call(
SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
feat.set_value.assert_called_once()
feat.set_value.reset_mock()
@ -249,7 +251,7 @@ async def test_strip_unique_ids(
features=["state", "led"],
)
with _patch_discovery(device=strip), _patch_connect(device=strip):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
for plug_id in range(2):
@ -264,7 +266,7 @@ async def test_strip_blank_alias(
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test a strip unique id."""
"""Test a strip with blank parent alias."""
already_migrated_config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
)
@ -276,7 +278,7 @@ async def test_strip_blank_alias(
features=["state", "led"],
)
with _patch_discovery(device=strip), _patch_connect(device=strip):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
strip_entity_id = "switch.unnamed_ks123"
@ -338,7 +340,7 @@ async def test_plug_errors_when_turned_on(
feat.set_value.side_effect = exception_type("test error")
with _patch_discovery(device=plug), _patch_connect(device=plug):
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.config_entries.async_setup(already_migrated_config_entry.entry_id)
await hass.async_block_till_done()
entity_id = "switch.my_plug"
@ -349,7 +351,7 @@ async def test_plug_errors_when_turned_on(
with pytest.raises(HomeAssistantError, match=msg):
await hass.services.async_call(
SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True
)
await hass.async_block_till_done()
assert feat.set_value.call_count == 1