mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Fix default turn_on without explicit preset or percentage in Matter Fan platform (#122591)
This commit is contained in:
parent
745eea9a29
commit
85aca4f095
@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.common.helpers.util import create_attribute_path_from_attribute
|
||||
@ -57,6 +57,7 @@ class MatterFan(MatterEntity, FanEntity):
|
||||
"""Representation of a Matter fan."""
|
||||
|
||||
_last_known_preset_mode: str | None = None
|
||||
_last_known_percentage: int = 0
|
||||
_enable_turn_on_off_backwards_compatibility = False
|
||||
|
||||
async def async_turn_on(
|
||||
@ -66,14 +67,27 @@ class MatterFan(MatterEntity, FanEntity):
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Turn on the fan."""
|
||||
if percentage is None and preset_mode is None:
|
||||
# turn_on without explicit percentage or preset_mode given
|
||||
# try to handle this with the last known value
|
||||
if self._last_known_percentage != 0:
|
||||
percentage = self._last_known_percentage
|
||||
elif self._last_known_preset_mode is not None:
|
||||
preset_mode = self._last_known_preset_mode
|
||||
elif self._attr_preset_modes:
|
||||
# fallback: default to first supported preset
|
||||
preset_mode = self._attr_preset_modes[0]
|
||||
else:
|
||||
# this really should not be possible but handle it anyways
|
||||
percentage = 50
|
||||
|
||||
# prefer setting fan speed by percentage
|
||||
if percentage is not None:
|
||||
# handle setting fan speed by percentage
|
||||
await self.async_set_percentage(percentage)
|
||||
return
|
||||
# handle setting fan mode by preset
|
||||
if preset_mode is None:
|
||||
# no preset given, try to handle this with the last known value
|
||||
preset_mode = self._last_known_preset_mode or PRESET_AUTO
|
||||
if TYPE_CHECKING:
|
||||
assert preset_mode is not None
|
||||
await self.async_set_preset_mode(preset_mode)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
@ -236,6 +250,8 @@ class MatterFan(MatterEntity, FanEntity):
|
||||
# keep track of the last known mode for turn_on commands without preset
|
||||
if self._attr_preset_mode is not None:
|
||||
self._last_known_preset_mode = self._attr_preset_mode
|
||||
if current_percent:
|
||||
self._last_known_percentage = current_percent
|
||||
|
||||
@callback
|
||||
def _calculate_features(
|
||||
@ -276,8 +292,10 @@ class MatterFan(MatterEntity, FanEntity):
|
||||
preset_modes = [PRESET_LOW, PRESET_MEDIUM, PRESET_HIGH]
|
||||
elif fan_mode_seq == FanModeSequenceEnum.kOffLowMedHighAuto:
|
||||
preset_modes = [PRESET_LOW, PRESET_MEDIUM, PRESET_HIGH, PRESET_AUTO]
|
||||
elif fan_mode_seq == FanModeSequenceEnum.kOffOnAuto:
|
||||
preset_modes = [PRESET_AUTO]
|
||||
elif fan_mode_seq == FanModeSequenceEnum.kOffHighAuto:
|
||||
preset_modes = [PRESET_HIGH, PRESET_AUTO]
|
||||
elif fan_mode_seq == FanModeSequenceEnum.kOffHigh:
|
||||
preset_modes = [PRESET_HIGH]
|
||||
# treat Matter Wind feature as additional preset(s)
|
||||
if feature_map & FanControlFeature.kWind:
|
||||
wind_support = int(
|
||||
|
@ -124,6 +124,7 @@ DISCOVERY_SCHEMAS = [
|
||||
device_types.Cooktop,
|
||||
device_types.Dishwasher,
|
||||
device_types.ExtractorHood,
|
||||
device_types.Fan,
|
||||
device_types.HeatingCoolingUnit,
|
||||
device_types.LaundryDryer,
|
||||
device_types.LaundryWasher,
|
||||
|
@ -31,9 +31,12 @@ async def setup_integration_with_node_fixture(
|
||||
hass: HomeAssistant,
|
||||
node_fixture: str,
|
||||
client: MagicMock,
|
||||
override_attributes: dict[str, Any] | None = None,
|
||||
) -> MatterNode:
|
||||
"""Set up Matter integration with fixture as node."""
|
||||
node_data = load_and_parse_node_fixture(node_fixture)
|
||||
if override_attributes:
|
||||
node_data["attributes"].update(override_attributes)
|
||||
node = MatterNode(
|
||||
dataclass_from_dict(
|
||||
MatterNodeData,
|
||||
|
340
tests/components/matter/fixtures/nodes/fan.json
Normal file
340
tests/components/matter/fixtures/nodes/fan.json
Normal file
@ -0,0 +1,340 @@
|
||||
{
|
||||
"node_id": 29,
|
||||
"date_commissioned": "2024-07-25T08:34:23.014310",
|
||||
"last_interview": "2024-07-25T08:34:23.014315",
|
||||
"interview_version": 6,
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attributes": {
|
||||
"0/29/0": [
|
||||
{
|
||||
"0": 18,
|
||||
"1": 1
|
||||
},
|
||||
{
|
||||
"0": 22,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"0/29/1": [29, 31, 40, 42, 48, 49, 51, 53, 60, 62, 63, 64],
|
||||
"0/29/2": [41],
|
||||
"0/29/3": [1, 2, 3, 4, 5, 6],
|
||||
"0/29/65532": 0,
|
||||
"0/29/65533": 2,
|
||||
"0/29/65528": [],
|
||||
"0/29/65529": [],
|
||||
"0/29/65530": [],
|
||||
"0/29/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/31/0": [
|
||||
{
|
||||
"1": 5,
|
||||
"2": 2,
|
||||
"3": [112233],
|
||||
"4": null,
|
||||
"254": 5
|
||||
}
|
||||
],
|
||||
"0/31/1": [],
|
||||
"0/31/2": 4,
|
||||
"0/31/3": 3,
|
||||
"0/31/4": 4,
|
||||
"0/31/65532": 0,
|
||||
"0/31/65533": 1,
|
||||
"0/31/65528": [],
|
||||
"0/31/65529": [],
|
||||
"0/31/65530": [0, 1],
|
||||
"0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/40/0": 17,
|
||||
"0/40/1": "Mock",
|
||||
"0/40/2": 4961,
|
||||
"0/40/3": "Fan",
|
||||
"0/40/4": 2,
|
||||
"0/40/5": "Mocked Fan Switch",
|
||||
"0/40/6": "**REDACTED**",
|
||||
"0/40/7": 1,
|
||||
"0/40/8": "1.0",
|
||||
"0/40/9": 4,
|
||||
"0/40/10": "0.0.1",
|
||||
"0/40/11": "",
|
||||
"0/40/12": "",
|
||||
"0/40/13": "",
|
||||
"0/40/14": "",
|
||||
"0/40/15": "",
|
||||
"0/40/16": false,
|
||||
"0/40/17": true,
|
||||
"0/40/18": "",
|
||||
"0/40/19": {
|
||||
"0": 3,
|
||||
"1": 3
|
||||
},
|
||||
"0/40/65532": 0,
|
||||
"0/40/65533": 2,
|
||||
"0/40/65528": [],
|
||||
"0/40/65529": [],
|
||||
"0/40/65530": [0],
|
||||
"0/40/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
65528, 65529, 65530, 65531, 65532, 65533
|
||||
],
|
||||
"0/42/0": [],
|
||||
"0/42/1": true,
|
||||
"0/42/2": 1,
|
||||
"0/42/3": null,
|
||||
"0/42/65532": 0,
|
||||
"0/42/65533": 1,
|
||||
"0/42/65528": [],
|
||||
"0/42/65529": [0],
|
||||
"0/42/65530": [0, 1, 2],
|
||||
"0/42/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/48/0": 0,
|
||||
"0/48/1": {
|
||||
"0": 60,
|
||||
"1": 900
|
||||
},
|
||||
"0/48/2": 0,
|
||||
"0/48/3": 0,
|
||||
"0/48/4": true,
|
||||
"0/48/65532": 0,
|
||||
"0/48/65533": 1,
|
||||
"0/48/65528": [1, 3, 5],
|
||||
"0/48/65529": [0, 2, 4],
|
||||
"0/48/65530": [],
|
||||
"0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/49/0": 1,
|
||||
"0/49/1": [
|
||||
{
|
||||
"0": "J/YquJb4Ao4=",
|
||||
"1": true
|
||||
}
|
||||
],
|
||||
"0/49/2": 10,
|
||||
"0/49/3": 20,
|
||||
"0/49/4": true,
|
||||
"0/49/5": 0,
|
||||
"0/49/6": "J/YquJb4Ao4=",
|
||||
"0/49/7": null,
|
||||
"0/49/65532": 2,
|
||||
"0/49/65533": 1,
|
||||
"0/49/65528": [1, 5, 7],
|
||||
"0/49/65529": [0, 3, 4, 6, 8],
|
||||
"0/49/65530": [],
|
||||
"0/49/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 65528, 65529, 65530, 65531, 65532, 65533
|
||||
],
|
||||
"0/51/0": [],
|
||||
"0/51/1": 15,
|
||||
"0/51/2": 5688,
|
||||
"0/51/3": 1,
|
||||
"0/51/4": 0,
|
||||
"0/51/5": [],
|
||||
"0/51/6": [],
|
||||
"0/51/7": [],
|
||||
"0/51/8": false,
|
||||
"0/51/65532": 0,
|
||||
"0/51/65533": 1,
|
||||
"0/51/65528": [],
|
||||
"0/51/65529": [0],
|
||||
"0/51/65530": [3],
|
||||
"0/51/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 65528, 65529, 65530, 65531, 65532, 65533
|
||||
],
|
||||
"0/53/0": 25,
|
||||
"0/53/1": 5,
|
||||
"0/53/2": "ha-thread",
|
||||
"0/53/3": 12768,
|
||||
"0/53/4": 5924944741529093989,
|
||||
"0/53/5": "",
|
||||
"0/53/6": 0,
|
||||
"0/53/7": [],
|
||||
"0/53/8": [],
|
||||
"0/53/9": 933034070,
|
||||
"0/53/10": 68,
|
||||
"0/53/11": 16,
|
||||
"0/53/12": 151,
|
||||
"0/53/13": 31,
|
||||
"0/53/14": 1,
|
||||
"0/53/15": 0,
|
||||
"0/53/16": 1,
|
||||
"0/53/17": 0,
|
||||
"0/53/18": 0,
|
||||
"0/53/19": 1,
|
||||
"0/53/20": 0,
|
||||
"0/53/21": 0,
|
||||
"0/53/22": 3533,
|
||||
"0/53/23": 3105,
|
||||
"0/53/24": 428,
|
||||
"0/53/25": 1889,
|
||||
"0/53/26": 1879,
|
||||
"0/53/27": 1644,
|
||||
"0/53/28": 2317,
|
||||
"0/53/29": 0,
|
||||
"0/53/30": 1216,
|
||||
"0/53/31": 0,
|
||||
"0/53/32": 0,
|
||||
"0/53/33": 534,
|
||||
"0/53/34": 10,
|
||||
"0/53/35": 0,
|
||||
"0/53/36": 42,
|
||||
"0/53/37": 0,
|
||||
"0/53/38": 0,
|
||||
"0/53/39": 18130,
|
||||
"0/53/40": 12178,
|
||||
"0/53/41": 5863,
|
||||
"0/53/42": 5103,
|
||||
"0/53/43": 0,
|
||||
"0/53/44": 11639,
|
||||
"0/53/45": 1216,
|
||||
"0/53/46": 0,
|
||||
"0/53/47": 0,
|
||||
"0/53/48": 0,
|
||||
"0/53/49": 14,
|
||||
"0/53/50": 0,
|
||||
"0/53/51": 89,
|
||||
"0/53/52": 0,
|
||||
"0/53/53": 69,
|
||||
"0/53/54": 0,
|
||||
"0/53/55": 0,
|
||||
"0/53/56": 131072,
|
||||
"0/53/57": 0,
|
||||
"0/53/58": 0,
|
||||
"0/53/59": {
|
||||
"0": 672,
|
||||
"1": 8335
|
||||
},
|
||||
"0/53/60": "AB//4A==",
|
||||
"0/53/61": {
|
||||
"0": true,
|
||||
"1": false,
|
||||
"2": true,
|
||||
"3": true,
|
||||
"4": true,
|
||||
"5": true,
|
||||
"6": false,
|
||||
"7": true,
|
||||
"8": true,
|
||||
"9": true,
|
||||
"10": true,
|
||||
"11": true
|
||||
},
|
||||
"0/53/62": [0, 0, 0, 0],
|
||||
"0/53/65532": 15,
|
||||
"0/53/65533": 1,
|
||||
"0/53/65528": [],
|
||||
"0/53/65529": [0],
|
||||
"0/53/65530": [],
|
||||
"0/53/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
||||
57, 58, 59, 60, 61, 62, 65528, 65529, 65530, 65531, 65532, 65533
|
||||
],
|
||||
"0/60/0": 0,
|
||||
"0/60/1": null,
|
||||
"0/60/2": null,
|
||||
"0/60/65532": 0,
|
||||
"0/60/65533": 1,
|
||||
"0/60/65528": [],
|
||||
"0/60/65529": [0, 1, 2],
|
||||
"0/60/65530": [],
|
||||
"0/60/65531": [0, 1, 2, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/62/0": [],
|
||||
"0/62/1": [],
|
||||
"0/62/2": 5,
|
||||
"0/62/3": 4,
|
||||
"0/62/4": [],
|
||||
"0/62/5": 5,
|
||||
"0/62/65532": 0,
|
||||
"0/62/65533": 1,
|
||||
"0/62/65528": [1, 3, 5, 8],
|
||||
"0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11],
|
||||
"0/62/65530": [],
|
||||
"0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/63/0": [],
|
||||
"0/63/1": [],
|
||||
"0/63/2": 4,
|
||||
"0/63/3": 3,
|
||||
"0/63/65532": 0,
|
||||
"0/63/65533": 2,
|
||||
"0/63/65528": [2, 5],
|
||||
"0/63/65529": [0, 1, 3, 4],
|
||||
"0/63/65530": [],
|
||||
"0/63/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"0/64/0": [
|
||||
{
|
||||
"0": "Vendor",
|
||||
"1": "Mocked"
|
||||
},
|
||||
{
|
||||
"0": "Product",
|
||||
"1": "Fan"
|
||||
}
|
||||
],
|
||||
"0/64/65532": 0,
|
||||
"0/64/65533": 1,
|
||||
"0/64/65528": [],
|
||||
"0/64/65529": [],
|
||||
"0/64/65530": [],
|
||||
"0/64/65531": [0, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/3/0": 0,
|
||||
"1/3/1": 2,
|
||||
"1/3/65532": 0,
|
||||
"1/3/65533": 4,
|
||||
"1/3/65528": [],
|
||||
"1/3/65529": [0, 64],
|
||||
"1/3/65530": [],
|
||||
"1/3/65531": [0, 1, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/4/0": 128,
|
||||
"1/4/65532": 1,
|
||||
"1/4/65533": 4,
|
||||
"1/4/65528": [0, 1, 2, 3],
|
||||
"1/4/65529": [0, 1, 2, 3, 4, 5],
|
||||
"1/4/65530": [],
|
||||
"1/4/65531": [0, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/29/0": [
|
||||
{
|
||||
"0": 43,
|
||||
"1": 1
|
||||
}
|
||||
],
|
||||
"1/29/1": [3, 4, 6, 8, 29, 64, 80, 514, 305134641],
|
||||
"1/29/2": [],
|
||||
"1/29/3": [],
|
||||
"1/29/65532": 0,
|
||||
"1/29/65533": 2,
|
||||
"1/29/65528": [],
|
||||
"1/29/65529": [],
|
||||
"1/29/65530": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
"1/64/0": [
|
||||
{
|
||||
"0": "DeviceType",
|
||||
"1": "Fan"
|
||||
}
|
||||
],
|
||||
"1/64/65532": 0,
|
||||
"1/64/65533": 1,
|
||||
"1/64/65528": [],
|
||||
"1/64/65529": [],
|
||||
"1/64/65530": [],
|
||||
"1/64/65531": [0, 65528, 65529, 65530, 65531, 65532, 65533],
|
||||
|
||||
"1/514/0": 8,
|
||||
"1/514/1": 2,
|
||||
"1/514/2": 0,
|
||||
"1/514/3": 0,
|
||||
"1/514/4": 3,
|
||||
"1/514/5": 0,
|
||||
"1/514/6": 0,
|
||||
"1/514/9": 3,
|
||||
"1/514/10": 0,
|
||||
"1/514/65532": 25,
|
||||
"1/514/65533": 4,
|
||||
"1/514/65528": [],
|
||||
"1/514/65529": [0],
|
||||
"1/514/65530": [],
|
||||
"1/514/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 9, 10, 65528, 65529, 65530, 65531, 65532, 65533
|
||||
]
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
"""Test Matter Fan platform."""
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
from matter_server.client.models.node import MatterNode
|
||||
@ -27,6 +28,14 @@ from .common import (
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="fan_node")
|
||||
async def simple_fan_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a Fan node."""
|
||||
return await setup_integration_with_node_fixture(hass, "fan", matter_client)
|
||||
|
||||
|
||||
@pytest.fixture(name="air_purifier")
|
||||
async def air_purifier_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
@ -100,6 +109,7 @@ async def test_fan_base(
|
||||
assert state.attributes["percentage"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_fan_turn_on_with_percentage(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
@ -119,15 +129,31 @@ async def test_fan_turn_on_with_percentage(
|
||||
attribute_path="1/514/2",
|
||||
value=50,
|
||||
)
|
||||
# test again where preset_mode is omitted in the service call
|
||||
# which should select the last active percentage
|
||||
matter_client.write_attribute.reset_mock()
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 1
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=air_purifier.node_id,
|
||||
attribute_path="1/514/2",
|
||||
value=255,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
async def test_fan_turn_on_with_preset_mode(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
air_purifier: MatterNode,
|
||||
fan_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test turning on the fan with a specific preset mode."""
|
||||
entity_id = "fan.air_purifier_fan"
|
||||
entity_id = "fan.mocked_fan_switch_fan"
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
@ -136,7 +162,7 @@ async def test_fan_turn_on_with_preset_mode(
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 1
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=air_purifier.node_id,
|
||||
node_id=fan_node.node_id,
|
||||
attribute_path="1/514/0",
|
||||
value=2,
|
||||
)
|
||||
@ -151,28 +177,13 @@ async def test_fan_turn_on_with_preset_mode(
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 1
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=air_purifier.node_id,
|
||||
node_id=fan_node.node_id,
|
||||
attribute_path="1/514/10",
|
||||
value=value,
|
||||
)
|
||||
# test again where preset_mode is omitted in the service call
|
||||
# which should select a default preset mode
|
||||
matter_client.write_attribute.reset_mock()
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 1
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=air_purifier.node_id,
|
||||
attribute_path="1/514/0",
|
||||
value=5,
|
||||
)
|
||||
# test again if wind mode is explicitly turned off when we set a new preset mode
|
||||
matter_client.write_attribute.reset_mock()
|
||||
set_node_attribute(air_purifier, 1, 514, 10, 2)
|
||||
set_node_attribute(fan_node, 1, 514, 10, 2)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
@ -182,15 +193,33 @@ async def test_fan_turn_on_with_preset_mode(
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 2
|
||||
assert matter_client.write_attribute.call_args_list[0] == call(
|
||||
node_id=air_purifier.node_id,
|
||||
node_id=fan_node.node_id,
|
||||
attribute_path="1/514/10",
|
||||
value=0,
|
||||
)
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=air_purifier.node_id,
|
||||
node_id=fan_node.node_id,
|
||||
attribute_path="1/514/0",
|
||||
value=2,
|
||||
)
|
||||
# test again where preset_mode is omitted in the service call
|
||||
# which should select the last active preset
|
||||
matter_client.write_attribute.reset_mock()
|
||||
set_node_attribute(fan_node, 1, 514, 0, 1)
|
||||
set_node_attribute(fan_node, 1, 514, 10, 0)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
assert matter_client.write_attribute.call_count == 1
|
||||
assert matter_client.write_attribute.call_args == call(
|
||||
node_id=fan_node.node_id,
|
||||
attribute_path="1/514/0",
|
||||
value=1,
|
||||
)
|
||||
|
||||
|
||||
async def test_fan_turn_off(
|
||||
@ -279,3 +308,133 @@ async def test_fan_set_direction(
|
||||
value=value,
|
||||
)
|
||||
matter_client.write_attribute.reset_mock()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize(
|
||||
("fixture", "entity_id", "attributes", "features"),
|
||||
[
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{
|
||||
"1/514/65532": 0,
|
||||
},
|
||||
(FanEntityFeature.TURN_ON | FanEntityFeature.TURN_OFF),
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{
|
||||
"1/514/65532": 1,
|
||||
},
|
||||
(
|
||||
FanEntityFeature.TURN_ON
|
||||
| FanEntityFeature.TURN_OFF
|
||||
| FanEntityFeature.SET_SPEED
|
||||
),
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{
|
||||
"1/514/65532": 4,
|
||||
},
|
||||
(
|
||||
FanEntityFeature.TURN_ON
|
||||
| FanEntityFeature.TURN_OFF
|
||||
| FanEntityFeature.OSCILLATE
|
||||
),
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{
|
||||
"1/514/65532": 36,
|
||||
},
|
||||
(
|
||||
FanEntityFeature.TURN_ON
|
||||
| FanEntityFeature.TURN_OFF
|
||||
| FanEntityFeature.OSCILLATE
|
||||
| FanEntityFeature.DIRECTION
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_fan_supported_features(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
fixture: str,
|
||||
entity_id: str,
|
||||
attributes: dict[str, Any],
|
||||
features: int,
|
||||
) -> None:
|
||||
"""Test if the correct features get discovered from featuremap."""
|
||||
await setup_integration_with_node_fixture(hass, fixture, matter_client, attributes)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.attributes["supported_features"] & features == features
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@pytest.mark.parametrize(
|
||||
("fixture", "entity_id", "attributes", "preset_modes"),
|
||||
[
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 0, "1/514/65532": 0},
|
||||
[
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
],
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 1, "1/514/65532": 0},
|
||||
[
|
||||
"low",
|
||||
"high",
|
||||
],
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 2, "1/514/65532": 0},
|
||||
["low", "medium", "high", "auto"],
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 4, "1/514/65532": 0},
|
||||
["high", "auto"],
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 5, "1/514/65532": 0},
|
||||
["high"],
|
||||
),
|
||||
(
|
||||
"fan",
|
||||
"fan.mocked_fan_switch_fan",
|
||||
{"1/514/1": 5, "1/514/65532": 8, "1/514/9": 3},
|
||||
["high", "natural_wind", "sleep_wind"],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_fan_features(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
fixture: str,
|
||||
entity_id: str,
|
||||
attributes: dict[str, Any],
|
||||
preset_modes: list[str],
|
||||
) -> None:
|
||||
"""Test if the correct presets get discovered from fanmodesequence."""
|
||||
await setup_integration_with_node_fixture(hass, fixture, matter_client, attributes)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert state.attributes["preset_modes"] == preset_modes
|
||||
|
Loading…
x
Reference in New Issue
Block a user