mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 22:57:17 +00:00
Add homee fan platform (#143524)
* Initial fan * add more tests * add last fan tests and small fixes * fix tests after latest change * another small correction * use common strings * add snapshot test * fix review comments * fix typing * remove uneeded None * remove unwanted file * fix turn_on function * typo * Use constants for preset modes. * fix review notes.
This commit is contained in:
parent
cac0e0f6e8
commit
ba8d40f7d3
@ -19,6 +19,7 @@ PLATFORMS = [
|
|||||||
Platform.BUTTON,
|
Platform.BUTTON,
|
||||||
Platform.CLIMATE,
|
Platform.CLIMATE,
|
||||||
Platform.COVER,
|
Platform.COVER,
|
||||||
|
Platform.FAN,
|
||||||
Platform.LIGHT,
|
Platform.LIGHT,
|
||||||
Platform.LOCK,
|
Platform.LOCK,
|
||||||
Platform.NUMBER,
|
Platform.NUMBER,
|
||||||
|
@ -96,5 +96,7 @@ LIGHT_PROFILES = [
|
|||||||
NodeProfile.WIFI_ON_OFF_DIMMABLE_METERING_SWITCH,
|
NodeProfile.WIFI_ON_OFF_DIMMABLE_METERING_SWITCH,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Climate Presets
|
# Preset modes
|
||||||
|
PRESET_AUTO = "auto"
|
||||||
PRESET_MANUAL = "manual"
|
PRESET_MANUAL = "manual"
|
||||||
|
PRESET_SUMMER = "summer"
|
||||||
|
134
homeassistant/components/homee/fan.py
Normal file
134
homeassistant/components/homee/fan.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
"""The Homee fan platform."""
|
||||||
|
|
||||||
|
import math
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
|
from pyHomee.const import AttributeType, NodeProfile
|
||||||
|
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||||
|
|
||||||
|
from homeassistant.components.fan import FanEntity, FanEntityFeature
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
from homeassistant.util.percentage import (
|
||||||
|
percentage_to_ranged_value,
|
||||||
|
ranged_value_to_percentage,
|
||||||
|
)
|
||||||
|
from homeassistant.util.scaling import int_states_in_range
|
||||||
|
|
||||||
|
from . import HomeeConfigEntry
|
||||||
|
from .const import DOMAIN, PRESET_AUTO, PRESET_MANUAL, PRESET_SUMMER
|
||||||
|
from .entity import HomeeNodeEntity
|
||||||
|
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: HomeeConfigEntry,
|
||||||
|
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the Homee fan platform."""
|
||||||
|
|
||||||
|
async_add_devices(
|
||||||
|
HomeeFan(node, config_entry)
|
||||||
|
for node in config_entry.runtime_data.nodes
|
||||||
|
if node.profile == NodeProfile.VENTILATION_CONTROL
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HomeeFan(HomeeNodeEntity, FanEntity):
|
||||||
|
"""Representation of a Homee fan entity."""
|
||||||
|
|
||||||
|
_attr_translation_key = DOMAIN
|
||||||
|
_attr_name = None
|
||||||
|
_attr_preset_modes = [PRESET_MANUAL, PRESET_AUTO, PRESET_SUMMER]
|
||||||
|
speed_range = (1, 8)
|
||||||
|
_attr_speed_count = int_states_in_range(speed_range)
|
||||||
|
|
||||||
|
def __init__(self, node: HomeeNode, entry: HomeeConfigEntry) -> None:
|
||||||
|
"""Initialize a Homee fan entity."""
|
||||||
|
super().__init__(node, entry)
|
||||||
|
self._speed_attribute: HomeeAttribute = cast(
|
||||||
|
HomeeAttribute, node.get_attribute_by_type(AttributeType.VENTILATION_LEVEL)
|
||||||
|
)
|
||||||
|
self._mode_attribute: HomeeAttribute = cast(
|
||||||
|
HomeeAttribute, node.get_attribute_by_type(AttributeType.VENTILATION_MODE)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self) -> FanEntityFeature:
|
||||||
|
"""Return the supported features based on preset_mode."""
|
||||||
|
features = FanEntityFeature.PRESET_MODE
|
||||||
|
|
||||||
|
if self.preset_mode == PRESET_MANUAL:
|
||||||
|
features |= (
|
||||||
|
FanEntityFeature.SET_SPEED
|
||||||
|
| FanEntityFeature.TURN_ON
|
||||||
|
| FanEntityFeature.TURN_OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
return features
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Return true if the entity is on."""
|
||||||
|
return self.percentage > 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def percentage(self) -> int:
|
||||||
|
"""Return the current speed percentage."""
|
||||||
|
return ranged_value_to_percentage(
|
||||||
|
self.speed_range, self._speed_attribute.current_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preset_mode(self) -> str:
|
||||||
|
"""Return the mode from the float state."""
|
||||||
|
return self._attr_preset_modes[int(self._mode_attribute.current_value)]
|
||||||
|
|
||||||
|
async def async_set_percentage(self, percentage: int) -> None:
|
||||||
|
"""Set the speed percentage of the fan."""
|
||||||
|
await self.async_set_homee_value(
|
||||||
|
self._speed_attribute,
|
||||||
|
math.ceil(percentage_to_ranged_value(self.speed_range, percentage)),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||||
|
"""Set the preset mode of the fan."""
|
||||||
|
await self.async_set_homee_value(
|
||||||
|
self._mode_attribute, self._attr_preset_modes.index(preset_mode)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the fan off."""
|
||||||
|
await self.async_set_homee_value(self._speed_attribute, 0)
|
||||||
|
|
||||||
|
async def async_turn_on(
|
||||||
|
self,
|
||||||
|
percentage: int | None = None,
|
||||||
|
preset_mode: str | None = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> None:
|
||||||
|
"""Turn the fan on."""
|
||||||
|
if preset_mode is not None:
|
||||||
|
if preset_mode != "manual":
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_preset_mode",
|
||||||
|
translation_placeholders={"preset_mode": preset_mode},
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.async_set_preset_mode(preset_mode)
|
||||||
|
|
||||||
|
# If no percentage is given, use the last known value.
|
||||||
|
if percentage is None:
|
||||||
|
percentage = ranged_value_to_percentage(
|
||||||
|
self.speed_range,
|
||||||
|
self._speed_attribute.last_value,
|
||||||
|
)
|
||||||
|
# If the last known value is 0, set 100%.
|
||||||
|
if percentage == 0:
|
||||||
|
percentage = 100
|
||||||
|
|
||||||
|
await self.async_set_percentage(percentage)
|
@ -11,6 +11,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fan": {
|
||||||
|
"homee": {
|
||||||
|
"state_attributes": {
|
||||||
|
"preset_mode": {
|
||||||
|
"state": {
|
||||||
|
"manual": "mdi:hand-back-left",
|
||||||
|
"auto": "mdi:auto-mode",
|
||||||
|
"summer": "mdi:sun-thermometer-outline"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"brightness": {
|
"brightness": {
|
||||||
"default": "mdi:brightness-5"
|
"default": "mdi:brightness-5"
|
||||||
|
@ -142,6 +142,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fan": {
|
||||||
|
"homee": {
|
||||||
|
"state_attributes": {
|
||||||
|
"preset_mode": {
|
||||||
|
"state": {
|
||||||
|
"manual": "[%key:common::state::manual%]",
|
||||||
|
"auto": "[%key:common::state::auto%]",
|
||||||
|
"summer": "Summer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"light": {
|
"light": {
|
||||||
"light_instance": {
|
"light_instance": {
|
||||||
"name": "Light {instance}"
|
"name": "Light {instance}"
|
||||||
@ -356,6 +369,9 @@
|
|||||||
"exceptions": {
|
"exceptions": {
|
||||||
"connection_closed": {
|
"connection_closed": {
|
||||||
"message": "Could not connect to homee while setting attribute."
|
"message": "Could not connect to homee while setting attribute."
|
||||||
|
},
|
||||||
|
"invalid_preset_mode": {
|
||||||
|
"message": "Invalid preset mode: {preset_mode}. Turning on is only supported with preset mode 'Manual'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
|
73
tests/components/homee/fixtures/fan.json
Normal file
73
tests/components/homee/fixtures/fan.json
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"id": 77,
|
||||||
|
"name": "Test Fan",
|
||||||
|
"profile": 3019,
|
||||||
|
"image": "default",
|
||||||
|
"favorite": 0,
|
||||||
|
"order": 76,
|
||||||
|
"protocol": 3,
|
||||||
|
"routing": 0,
|
||||||
|
"state": 1,
|
||||||
|
"state_changed": 1736106044,
|
||||||
|
"added": 1723550156,
|
||||||
|
"history": 1,
|
||||||
|
"cube_type": 3,
|
||||||
|
"note": "",
|
||||||
|
"services": 1,
|
||||||
|
"phonetic_name": "",
|
||||||
|
"owner": 2,
|
||||||
|
"security": 0,
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"node_id": 77,
|
||||||
|
"instance": 0,
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 8,
|
||||||
|
"current_value": 3.0,
|
||||||
|
"target_value": 3.0,
|
||||||
|
"last_value": 6.0,
|
||||||
|
"unit": "n/a",
|
||||||
|
"step_value": 1.0,
|
||||||
|
"editable": 1,
|
||||||
|
"type": 99,
|
||||||
|
"state": 5,
|
||||||
|
"last_changed": 1729920212,
|
||||||
|
"changed_by": 1,
|
||||||
|
"changed_by_id": 0,
|
||||||
|
"based_on": 1,
|
||||||
|
"data": "",
|
||||||
|
"name": "",
|
||||||
|
"options": {
|
||||||
|
"automations": ["step"],
|
||||||
|
"history": {
|
||||||
|
"day": 35,
|
||||||
|
"week": 5,
|
||||||
|
"month": 1,
|
||||||
|
"stepped": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"node_id": 77,
|
||||||
|
"instance": 0,
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 2,
|
||||||
|
"current_value": 0.0,
|
||||||
|
"target_value": 0.0,
|
||||||
|
"last_value": 1.0,
|
||||||
|
"unit": "n/a",
|
||||||
|
"step_value": 1.0,
|
||||||
|
"editable": 1,
|
||||||
|
"type": 100,
|
||||||
|
"state": 1,
|
||||||
|
"last_changed": 1736106312,
|
||||||
|
"changed_by": 1,
|
||||||
|
"changed_by_id": 0,
|
||||||
|
"based_on": 1,
|
||||||
|
"data": "",
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
63
tests/components/homee/snapshots/test_fan.ambr
Normal file
63
tests/components/homee/snapshots/test_fan.ambr
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_fan_snapshot[fan.test_fan-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'preset_modes': list([
|
||||||
|
'manual',
|
||||||
|
'auto',
|
||||||
|
'summer',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'fan',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'fan.test_fan',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': None,
|
||||||
|
'platform': 'homee',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': <FanEntityFeature: 57>,
|
||||||
|
'translation_key': 'homee',
|
||||||
|
'unique_id': '00055511EECC-77',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_fan_snapshot[fan.test_fan-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test Fan',
|
||||||
|
'percentage': 37,
|
||||||
|
'percentage_step': 12.5,
|
||||||
|
'preset_mode': 'manual',
|
||||||
|
'preset_modes': list([
|
||||||
|
'manual',
|
||||||
|
'auto',
|
||||||
|
'summer',
|
||||||
|
]),
|
||||||
|
'supported_features': <FanEntityFeature: 57>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'fan.test_fan',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'on',
|
||||||
|
})
|
||||||
|
# ---
|
192
tests/components/homee/test_fan.py
Normal file
192
tests/components/homee/test_fan.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
"""Test Homee fans."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.fan import (
|
||||||
|
ATTR_PERCENTAGE,
|
||||||
|
ATTR_PRESET_MODE,
|
||||||
|
DOMAIN as FAN_DOMAIN,
|
||||||
|
SERVICE_DECREASE_SPEED,
|
||||||
|
SERVICE_INCREASE_SPEED,
|
||||||
|
SERVICE_SET_PERCENTAGE,
|
||||||
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
SERVICE_TOGGLE,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
)
|
||||||
|
from homeassistant.components.homee.const import (
|
||||||
|
DOMAIN,
|
||||||
|
PRESET_AUTO,
|
||||||
|
PRESET_MANUAL,
|
||||||
|
PRESET_SUMMER,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import build_mock_node, setup_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("speed", "expected"),
|
||||||
|
[
|
||||||
|
(0, 0),
|
||||||
|
(1, 12),
|
||||||
|
(2, 25),
|
||||||
|
(3, 37),
|
||||||
|
(4, 50),
|
||||||
|
(5, 62),
|
||||||
|
(6, 75),
|
||||||
|
(7, 87),
|
||||||
|
(8, 100),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_percentage(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
speed: int,
|
||||||
|
expected: int,
|
||||||
|
) -> None:
|
||||||
|
"""Test percentage."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
mock_homee.nodes[0].attributes[0].current_value = speed
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert hass.states.get("fan.test_fan").attributes["percentage"] == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("mode_value", "expected"),
|
||||||
|
[
|
||||||
|
(0, "manual"),
|
||||||
|
(1, "auto"),
|
||||||
|
(2, "summer"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_preset_mode(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
mode_value: int,
|
||||||
|
expected: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test preset mode."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
mock_homee.nodes[0].attributes[1].current_value = mode_value
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert hass.states.get("fan.test_fan").attributes["preset_mode"] == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("service", "options", "expected"),
|
||||||
|
[
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 100}, (77, 1, 8)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 86}, (77, 1, 7)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 63}, (77, 1, 6)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 60}, (77, 1, 5)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 50}, (77, 1, 4)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 34}, (77, 1, 3)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 17}, (77, 1, 2)),
|
||||||
|
(SERVICE_TURN_ON, {ATTR_PERCENTAGE: 8}, (77, 1, 1)),
|
||||||
|
(SERVICE_TURN_ON, {}, (77, 1, 6)),
|
||||||
|
(SERVICE_TURN_OFF, {}, (77, 1, 0)),
|
||||||
|
(SERVICE_INCREASE_SPEED, {}, (77, 1, 4)),
|
||||||
|
(SERVICE_DECREASE_SPEED, {}, (77, 1, 2)),
|
||||||
|
(SERVICE_SET_PERCENTAGE, {ATTR_PERCENTAGE: 42}, (77, 1, 4)),
|
||||||
|
(SERVICE_SET_PRESET_MODE, {ATTR_PRESET_MODE: PRESET_MANUAL}, (77, 2, 0)),
|
||||||
|
(SERVICE_SET_PRESET_MODE, {ATTR_PRESET_MODE: PRESET_AUTO}, (77, 2, 1)),
|
||||||
|
(SERVICE_SET_PRESET_MODE, {ATTR_PRESET_MODE: PRESET_SUMMER}, (77, 2, 2)),
|
||||||
|
(SERVICE_TOGGLE, {}, (77, 1, 0)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_fan_services(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
service: str,
|
||||||
|
options: int | None,
|
||||||
|
expected: tuple[int, int, int],
|
||||||
|
) -> None:
|
||||||
|
"""Test fan services."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
OPTIONS = {ATTR_ENTITY_ID: "fan.test_fan"}
|
||||||
|
OPTIONS.update(options)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
FAN_DOMAIN,
|
||||||
|
service,
|
||||||
|
OPTIONS,
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_homee.set_value.assert_called_once_with(*expected)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_on_preset_last_value_zero(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test turn on with preset last value == 0."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
mock_homee.nodes[0].attributes[0].last_value = 0
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
FAN_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: "fan.test_fan", ATTR_PRESET_MODE: PRESET_MANUAL},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert mock_homee.set_value.call_args_list == [
|
||||||
|
call(77, 2, 0),
|
||||||
|
call(77, 1, 8),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_on_invalid_preset(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test turn on with invalid preset."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
with pytest.raises(ServiceValidationError) as exc_info:
|
||||||
|
await hass.services.async_call(
|
||||||
|
FAN_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: "fan.test_fan", ATTR_PRESET_MODE: PRESET_AUTO},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert exc_info.value.translation_domain == DOMAIN
|
||||||
|
assert exc_info.value.translation_key == "invalid_preset_mode"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fan_snapshot(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_homee: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test the fan snapshot."""
|
||||||
|
mock_homee.nodes = [build_mock_node("fan.json")]
|
||||||
|
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
|
||||||
|
with patch("homeassistant.components.homee.PLATFORMS", [Platform.FAN]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
Loading…
x
Reference in New Issue
Block a user