Files
core/tests/components/smartthings/test_sensor.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

394 lines
13 KiB
Python
Raw Normal View History

2025-02-26 15:14:04 +01:00
"""Test for the SmartThings sensors platform."""
2025-02-26 15:14:04 +01:00
from unittest.mock import AsyncMock
from pysmartthings import Attribute, Capability
from pysmartthings.models import HealthStatus
2025-02-26 15:14:04 +01:00
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import automation, script
from homeassistant.components.automation import automations_with_entity
from homeassistant.components.script import scripts_with_entity
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.smartthings.const import DOMAIN, MAIN
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.setup import async_setup_component
from . import (
setup_integration,
snapshot_smartthings_entities,
trigger_health_update,
trigger_update,
)
2025-02-26 15:14:04 +01:00
from tests.common import MockConfigEntry
2025-02-26 15:14:04 +01:00
async def test_all_entities(
hass: HomeAssistant,
2025-02-26 15:14:04 +01:00
snapshot: SnapshotAssertion,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
2025-02-26 15:14:04 +01:00
"""Test all entities."""
await setup_integration(hass, mock_config_entry)
2025-02-26 15:14:04 +01:00
snapshot_smartthings_entities(hass, entity_registry, snapshot, Platform.SENSOR)
@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"])
2025-02-26 15:14:04 +01:00
async def test_state_update(
hass: HomeAssistant,
2025-02-26 15:14:04 +01:00
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
2025-02-26 15:14:04 +01:00
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("sensor.ac_office_granit_temperature").state == "25"
2025-02-26 15:14:04 +01:00
await trigger_update(
hass,
devices,
"96a5ef74-5832-a84b-f1f7-ca799957065d",
Capability.TEMPERATURE_MEASUREMENT,
Attribute.TEMPERATURE,
20,
)
assert hass.states.get("sensor.ac_office_granit_temperature").state == "20"
@pytest.mark.parametrize(
(
"device_fixture",
"unique_id",
"suggested_object_id",
"issue_string",
"entity_id",
"expected_state",
"version",
),
[
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_PLAYBACK}_{Attribute.PLAYBACK_STATUS}_{Attribute.PLAYBACK_STATUS}",
"tv_samsung_8_series_49_media_playback_status",
"media_player",
"sensor.tv_samsung_8_series_49_media_playback_status",
STATE_UNKNOWN,
"2025.10.0",
),
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.AUDIO_VOLUME}_{Attribute.VOLUME}_{Attribute.VOLUME}",
"tv_samsung_8_series_49_volume",
"media_player",
"sensor.tv_samsung_8_series_49_volume",
"13",
"2025.10.0",
),
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_INPUT_SOURCE}_{Attribute.INPUT_SOURCE}_{Attribute.INPUT_SOURCE}",
"tv_samsung_8_series_49_media_input_source",
"media_player",
"sensor.tv_samsung_8_series_49_media_input_source",
"hdmi1",
"2025.10.0",
),
(
"im_speaker_ai_0001",
f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_REPEAT}_{Attribute.PLAYBACK_REPEAT_MODE}_{Attribute.PLAYBACK_REPEAT_MODE}",
"galaxy_home_mini_media_playback_repeat",
"media_player",
"sensor.galaxy_home_mini_media_playback_repeat",
"off",
"2025.10.0",
),
(
"im_speaker_ai_0001",
f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}",
"galaxy_home_mini_media_playback_shuffle",
"media_player",
"sensor.galaxy_home_mini_media_playback_shuffle",
"disabled",
"2025.10.0",
),
(
"da_ac_ehs_01001",
f"4165c51e-bf6b-c5b6-fd53-127d6248754b_{MAIN}_{Capability.TEMPERATURE_MEASUREMENT}_{Attribute.TEMPERATURE}_{Attribute.TEMPERATURE}",
"temperature",
"dhw",
"sensor.temperature",
"57",
"2025.12.0",
),
(
"da_ac_ehs_01001",
f"4165c51e-bf6b-c5b6-fd53-127d6248754b_{MAIN}_{Capability.THERMOSTAT_COOLING_SETPOINT}_{Attribute.COOLING_SETPOINT}_{Attribute.COOLING_SETPOINT}",
"cooling_setpoint",
"dhw",
"sensor.cooling_setpoint",
"56",
"2025.12.0",
),
],
)
async def test_create_issue_with_items(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
issue_registry: ir.IssueRegistry,
unique_id: str,
suggested_object_id: str,
issue_string: str,
entity_id: str,
expected_state: str,
version: str,
) -> None:
"""Test we create an issue when an automation or script is using a deprecated entity."""
issue_id = f"deprecated_{issue_string}_{entity_id}"
entity_entry = entity_registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
unique_id,
suggested_object_id=suggested_object_id,
original_name=suggested_object_id,
)
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"id": "test",
"alias": "test",
"trigger": {"platform": "state", "entity_id": entity_id},
"action": {
"action": "automation.turn_on",
"target": {
"entity_id": "automation.test",
},
},
}
},
)
assert await async_setup_component(
hass,
script.DOMAIN,
{
script.DOMAIN: {
"test": {
"sequence": [
{
"condition": "state",
"entity_id": entity_id,
"state": "on",
},
],
}
}
},
)
await setup_integration(hass, mock_config_entry)
assert hass.states.get(entity_id).state == expected_state
assert automations_with_entity(hass, entity_id)[0] == "automation.test"
assert scripts_with_entity(hass, entity_id)[0] == "script.test"
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
assert issue is not None
assert issue.translation_key == f"deprecated_{issue_string}_scripts"
assert issue.translation_placeholders == {
"entity_id": entity_id,
"entity_name": suggested_object_id,
"items": "- [test](/config/automation/edit/test)\n- [test](/config/script/edit/test)",
}
assert issue.breaks_in_ha_version == version
entity_registry.async_update_entity(
entity_entry.entity_id,
disabled_by=er.RegistryEntryDisabler.USER,
)
await hass.config_entries.async_reload(mock_config_entry.entry_id)
await hass.async_block_till_done()
# Assert the issue is no longer present
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
@pytest.mark.parametrize(
(
"device_fixture",
"unique_id",
"suggested_object_id",
"issue_string",
"entity_id",
"expected_state",
"version",
),
[
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_PLAYBACK}_{Attribute.PLAYBACK_STATUS}_{Attribute.PLAYBACK_STATUS}",
"tv_samsung_8_series_49_media_playback_status",
"media_player",
"sensor.tv_samsung_8_series_49_media_playback_status",
STATE_UNKNOWN,
"2025.10.0",
),
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.AUDIO_VOLUME}_{Attribute.VOLUME}_{Attribute.VOLUME}",
"tv_samsung_8_series_49_volume",
"media_player",
"sensor.tv_samsung_8_series_49_volume",
"13",
"2025.10.0",
),
(
"vd_stv_2017_k",
f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_INPUT_SOURCE}_{Attribute.INPUT_SOURCE}_{Attribute.INPUT_SOURCE}",
"tv_samsung_8_series_49_media_input_source",
"media_player",
"sensor.tv_samsung_8_series_49_media_input_source",
"hdmi1",
"2025.10.0",
),
(
"im_speaker_ai_0001",
f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_REPEAT}_{Attribute.PLAYBACK_REPEAT_MODE}_{Attribute.PLAYBACK_REPEAT_MODE}",
"galaxy_home_mini_media_playback_repeat",
"media_player",
"sensor.galaxy_home_mini_media_playback_repeat",
"off",
"2025.10.0",
),
(
"im_speaker_ai_0001",
f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}",
"galaxy_home_mini_media_playback_shuffle",
"media_player",
"sensor.galaxy_home_mini_media_playback_shuffle",
"disabled",
"2025.10.0",
),
(
"da_ac_ehs_01001",
f"4165c51e-bf6b-c5b6-fd53-127d6248754b_{MAIN}_{Capability.TEMPERATURE_MEASUREMENT}_{Attribute.TEMPERATURE}_{Attribute.TEMPERATURE}",
"temperature",
"dhw",
"sensor.temperature",
"57",
"2025.12.0",
),
(
"da_ac_ehs_01001",
f"4165c51e-bf6b-c5b6-fd53-127d6248754b_{MAIN}_{Capability.THERMOSTAT_COOLING_SETPOINT}_{Attribute.COOLING_SETPOINT}_{Attribute.COOLING_SETPOINT}",
"cooling_setpoint",
"dhw",
"sensor.cooling_setpoint",
"56",
"2025.12.0",
),
],
)
async def test_create_issue(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
issue_registry: ir.IssueRegistry,
unique_id: str,
suggested_object_id: str,
issue_string: str,
entity_id: str,
expected_state: str,
version: str,
) -> None:
"""Test we create an issue when an automation or script is using a deprecated entity."""
issue_id = f"deprecated_{issue_string}_{entity_id}"
entity_entry = entity_registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
unique_id,
suggested_object_id=suggested_object_id,
original_name=suggested_object_id,
)
await setup_integration(hass, mock_config_entry)
assert hass.states.get(entity_id).state == expected_state
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
assert issue is not None
assert issue.translation_key == f"deprecated_{issue_string}"
assert issue.translation_placeholders == {
"entity_id": entity_id,
"entity_name": suggested_object_id,
}
assert issue.breaks_in_ha_version == version
entity_registry.async_update_entity(
entity_entry.entity_id,
disabled_by=er.RegistryEntryDisabler.USER,
)
await hass.config_entries.async_reload(mock_config_entry.entry_id)
await hass.async_block_till_done()
# Assert the issue is no longer present
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"])
async def test_availability(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test availability."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("sensor.ac_office_granit_temperature").state == "25"
await trigger_health_update(
hass, devices, "96a5ef74-5832-a84b-f1f7-ca799957065d", HealthStatus.OFFLINE
)
assert (
hass.states.get("sensor.ac_office_granit_temperature").state
== STATE_UNAVAILABLE
)
await trigger_health_update(
hass, devices, "96a5ef74-5832-a84b-f1f7-ca799957065d", HealthStatus.ONLINE
)
assert hass.states.get("sensor.ac_office_granit_temperature").state == "25"
@pytest.mark.parametrize("device_fixture", ["da_ac_rac_000001"])
async def test_availability_at_start(
hass: HomeAssistant,
unavailable_device: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test unavailable at boot."""
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("sensor.ac_office_granit_temperature").state
== STATE_UNAVAILABLE
)