mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 16:57:10 +00:00
Add shutter_tilt support for Fibaro FGR 223 (#96283)
* add support for shutter_tilt for Fibaro FGR 223 add tests for fgr 223 * Adjust comments and docstring --------- Co-authored-by: Lennart <18117505+Ced4@users.noreply.github.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
b02f64196b
commit
9ab340047d
@ -160,6 +160,8 @@ class ZWaveValueDiscoverySchema(DataclassMustHaveAtLeastOne):
|
|||||||
writeable: bool | None = None
|
writeable: bool | None = None
|
||||||
# [optional] the value's states map must include ANY of these key/value pairs
|
# [optional] the value's states map must include ANY of these key/value pairs
|
||||||
any_available_states: set[tuple[int, str]] | None = None
|
any_available_states: set[tuple[int, str]] | None = None
|
||||||
|
# [optional] the value's value must match this value
|
||||||
|
value: Any | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -378,6 +380,61 @@ DISCOVERY_SCHEMAS = [
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
# Fibaro Shutter Fibaro FGR223
|
||||||
|
# Combine both switch_multilevel endpoints into shutter_tilt
|
||||||
|
# if operating mode (151) is set to venetian blind (2)
|
||||||
|
ZWaveDiscoverySchema(
|
||||||
|
platform=Platform.COVER,
|
||||||
|
hint="shutter_tilt",
|
||||||
|
manufacturer_id={0x010F},
|
||||||
|
product_id={0x1000, 0x1001},
|
||||||
|
product_type={0x0303},
|
||||||
|
primary_value=ZWaveValueDiscoverySchema(
|
||||||
|
command_class={CommandClass.SWITCH_MULTILEVEL},
|
||||||
|
property={CURRENT_VALUE_PROPERTY},
|
||||||
|
endpoint={1},
|
||||||
|
type={ValueType.NUMBER},
|
||||||
|
),
|
||||||
|
data_template=CoverTiltDataTemplate(
|
||||||
|
current_tilt_value_id=ZwaveValueID(
|
||||||
|
property_=CURRENT_VALUE_PROPERTY,
|
||||||
|
command_class=CommandClass.SWITCH_MULTILEVEL,
|
||||||
|
endpoint=2,
|
||||||
|
),
|
||||||
|
target_tilt_value_id=ZwaveValueID(
|
||||||
|
property_=TARGET_VALUE_PROPERTY,
|
||||||
|
command_class=CommandClass.SWITCH_MULTILEVEL,
|
||||||
|
endpoint=2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
required_values=[
|
||||||
|
ZWaveValueDiscoverySchema(
|
||||||
|
command_class={CommandClass.CONFIGURATION},
|
||||||
|
property={151},
|
||||||
|
endpoint={0},
|
||||||
|
value={2},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
# Fibaro Shutter Fibaro FGR223
|
||||||
|
# Disable endpoint 2 (slat),
|
||||||
|
# as these are either combined with endpoint one as shutter_tilt
|
||||||
|
# or it has no practical function.
|
||||||
|
# CC: Switch_Multilevel
|
||||||
|
ZWaveDiscoverySchema(
|
||||||
|
platform=Platform.COVER,
|
||||||
|
hint="shutter",
|
||||||
|
manufacturer_id={0x010F},
|
||||||
|
product_id={0x1000, 0x1001},
|
||||||
|
product_type={0x0303},
|
||||||
|
primary_value=ZWaveValueDiscoverySchema(
|
||||||
|
command_class={CommandClass.SWITCH_MULTILEVEL},
|
||||||
|
property={CURRENT_VALUE_PROPERTY},
|
||||||
|
endpoint={2},
|
||||||
|
type={ValueType.NUMBER},
|
||||||
|
),
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
# Fibaro Nice BiDi-ZWave (IBT4ZWAVE)
|
# Fibaro Nice BiDi-ZWave (IBT4ZWAVE)
|
||||||
ZWaveDiscoverySchema(
|
ZWaveDiscoverySchema(
|
||||||
platform=Platform.COVER,
|
platform=Platform.COVER,
|
||||||
@ -1236,6 +1293,9 @@ def check_value(value: ZwaveValue, schema: ZWaveValueDiscoverySchema) -> bool:
|
|||||||
)
|
)
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
# check value
|
||||||
|
if schema.value is not None and value.value not in schema.value:
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -483,6 +483,12 @@ def fibaro_fgr222_shutter_state_fixture():
|
|||||||
return json.loads(load_fixture("zwave_js/cover_fibaro_fgr222_state.json"))
|
return json.loads(load_fixture("zwave_js/cover_fibaro_fgr222_state.json"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="fibaro_fgr223_shutter_state", scope="session")
|
||||||
|
def fibaro_fgr223_shutter_state_fixture():
|
||||||
|
"""Load the Fibaro FGR223 node state fixture data."""
|
||||||
|
return json.loads(load_fixture("zwave_js/cover_fibaro_fgr223_state.json"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="merten_507801_state", scope="session")
|
@pytest.fixture(name="merten_507801_state", scope="session")
|
||||||
def merten_507801_state_fixture():
|
def merten_507801_state_fixture():
|
||||||
"""Load the Merten 507801 Shutter node state fixture data."""
|
"""Load the Merten 507801 Shutter node state fixture data."""
|
||||||
@ -1054,6 +1060,14 @@ def fibaro_fgr222_shutter_cover_fixture(client, fibaro_fgr222_shutter_state):
|
|||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="fibaro_fgr223_shutter")
|
||||||
|
def fibaro_fgr223_shutter_cover_fixture(client, fibaro_fgr223_shutter_state):
|
||||||
|
"""Mock a Fibaro FGR223 Shutter node."""
|
||||||
|
node = Node(client, copy.deepcopy(fibaro_fgr223_shutter_state))
|
||||||
|
client.driver.controller.nodes[node.node_id] = node
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="merten_507801")
|
@pytest.fixture(name="merten_507801")
|
||||||
def merten_507801_cover_fixture(client, merten_507801_state):
|
def merten_507801_cover_fixture(client, merten_507801_state):
|
||||||
"""Mock a Merten 507801 Shutter node."""
|
"""Mock a Merten 507801 Shutter node."""
|
||||||
|
2325
tests/components/zwave_js/fixtures/cover_fibaro_fgr223_state.json
Normal file
2325
tests/components/zwave_js/fixtures/cover_fibaro_fgr223_state.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,8 @@ GDC_COVER_ENTITY = "cover.aeon_labs_garage_door_controller_gen5"
|
|||||||
BLIND_COVER_ENTITY = "cover.window_blind_controller"
|
BLIND_COVER_ENTITY = "cover.window_blind_controller"
|
||||||
SHUTTER_COVER_ENTITY = "cover.flush_shutter"
|
SHUTTER_COVER_ENTITY = "cover.flush_shutter"
|
||||||
AEOTEC_SHUTTER_COVER_ENTITY = "cover.nano_shutter_v_3"
|
AEOTEC_SHUTTER_COVER_ENTITY = "cover.nano_shutter_v_3"
|
||||||
FIBARO_SHUTTER_COVER_ENTITY = "cover.fgr_222_test_cover"
|
FIBARO_FGR_222_SHUTTER_COVER_ENTITY = "cover.fgr_222_test_cover"
|
||||||
|
FIBARO_FGR_223_SHUTTER_COVER_ENTITY = "cover.fgr_223_test_cover"
|
||||||
LOGGER.setLevel(logging.DEBUG)
|
LOGGER.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
@ -238,7 +239,7 @@ async def test_fibaro_fgr222_shutter_cover(
|
|||||||
hass: HomeAssistant, client, fibaro_fgr222_shutter, integration
|
hass: HomeAssistant, client, fibaro_fgr222_shutter, integration
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test tilt function of the Fibaro Shutter devices."""
|
"""Test tilt function of the Fibaro Shutter devices."""
|
||||||
state = hass.states.get(FIBARO_SHUTTER_COVER_ENTITY)
|
state = hass.states.get(FIBARO_FGR_222_SHUTTER_COVER_ENTITY)
|
||||||
assert state
|
assert state
|
||||||
assert state.attributes[ATTR_DEVICE_CLASS] == CoverDeviceClass.SHUTTER
|
assert state.attributes[ATTR_DEVICE_CLASS] == CoverDeviceClass.SHUTTER
|
||||||
|
|
||||||
@ -249,7 +250,7 @@ async def test_fibaro_fgr222_shutter_cover(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_OPEN_COVER_TILT,
|
SERVICE_OPEN_COVER_TILT,
|
||||||
{ATTR_ENTITY_ID: FIBARO_SHUTTER_COVER_ENTITY},
|
{ATTR_ENTITY_ID: FIBARO_FGR_222_SHUTTER_COVER_ENTITY},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -271,7 +272,7 @@ async def test_fibaro_fgr222_shutter_cover(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_CLOSE_COVER_TILT,
|
SERVICE_CLOSE_COVER_TILT,
|
||||||
{ATTR_ENTITY_ID: FIBARO_SHUTTER_COVER_ENTITY},
|
{ATTR_ENTITY_ID: FIBARO_FGR_222_SHUTTER_COVER_ENTITY},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -293,7 +294,7 @@ async def test_fibaro_fgr222_shutter_cover(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_COVER_TILT_POSITION,
|
SERVICE_SET_COVER_TILT_POSITION,
|
||||||
{ATTR_ENTITY_ID: FIBARO_SHUTTER_COVER_ENTITY, ATTR_TILT_POSITION: 12},
|
{ATTR_ENTITY_ID: FIBARO_FGR_222_SHUTTER_COVER_ENTITY, ATTR_TILT_POSITION: 12},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -330,7 +331,101 @@ async def test_fibaro_fgr222_shutter_cover(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
fibaro_fgr222_shutter.receive_event(event)
|
fibaro_fgr222_shutter.receive_event(event)
|
||||||
state = hass.states.get(FIBARO_SHUTTER_COVER_ENTITY)
|
state = hass.states.get(FIBARO_FGR_222_SHUTTER_COVER_ENTITY)
|
||||||
|
assert state
|
||||||
|
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fibaro_fgr223_shutter_cover(
|
||||||
|
hass: HomeAssistant, client, fibaro_fgr223_shutter, integration
|
||||||
|
) -> None:
|
||||||
|
"""Test tilt function of the Fibaro Shutter devices."""
|
||||||
|
state = hass.states.get(FIBARO_FGR_223_SHUTTER_COVER_ENTITY)
|
||||||
|
assert state
|
||||||
|
assert state.attributes[ATTR_DEVICE_CLASS] == CoverDeviceClass.SHUTTER
|
||||||
|
|
||||||
|
assert state.state == STATE_OPEN
|
||||||
|
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 0
|
||||||
|
|
||||||
|
# Test opening tilts
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_OPEN_COVER_TILT,
|
||||||
|
{ATTR_ENTITY_ID: FIBARO_FGR_223_SHUTTER_COVER_ENTITY},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 10
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"endpoint": 2,
|
||||||
|
"commandClass": 38,
|
||||||
|
"property": "targetValue",
|
||||||
|
}
|
||||||
|
assert args["value"] == 99
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
# Test closing tilts
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_CLOSE_COVER_TILT,
|
||||||
|
{ATTR_ENTITY_ID: FIBARO_FGR_223_SHUTTER_COVER_ENTITY},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 10
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"endpoint": 2,
|
||||||
|
"commandClass": 38,
|
||||||
|
"property": "targetValue",
|
||||||
|
}
|
||||||
|
assert args["value"] == 0
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
# Test setting tilt position
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_COVER_TILT_POSITION,
|
||||||
|
{ATTR_ENTITY_ID: FIBARO_FGR_223_SHUTTER_COVER_ENTITY, ATTR_TILT_POSITION: 12},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 10
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"endpoint": 2,
|
||||||
|
"commandClass": 38,
|
||||||
|
"property": "targetValue",
|
||||||
|
}
|
||||||
|
assert args["value"] == 12
|
||||||
|
|
||||||
|
# Test some tilt
|
||||||
|
event = Event(
|
||||||
|
type="value updated",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value updated",
|
||||||
|
"nodeId": 10,
|
||||||
|
"args": {
|
||||||
|
"commandClassName": "Multilevel Switch",
|
||||||
|
"commandClass": 38,
|
||||||
|
"endpoint": 2,
|
||||||
|
"property": "currentValue",
|
||||||
|
"newValue": 99,
|
||||||
|
"prevValue": 0,
|
||||||
|
"propertyName": "currentValue",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
fibaro_fgr223_shutter.receive_event(event)
|
||||||
|
state = hass.states.get(FIBARO_FGR_223_SHUTTER_COVER_ENTITY)
|
||||||
assert state
|
assert state
|
||||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100
|
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100
|
||||||
|
|
||||||
@ -694,13 +789,42 @@ async def test_fibaro_fgr222_shutter_cover_no_tilt(
|
|||||||
client.driver.controller.emit("node added", {"node": node})
|
client.driver.controller.emit("node added", {"node": node})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(FIBARO_SHUTTER_COVER_ENTITY)
|
state = hass.states.get(FIBARO_FGR_222_SHUTTER_COVER_ENTITY)
|
||||||
assert state
|
assert state
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
assert ATTR_CURRENT_POSITION not in state.attributes
|
assert ATTR_CURRENT_POSITION not in state.attributes
|
||||||
assert ATTR_CURRENT_TILT_POSITION not in state.attributes
|
assert ATTR_CURRENT_TILT_POSITION not in state.attributes
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fibaro_fgr223_shutter_cover_no_tilt(
|
||||||
|
hass: HomeAssistant, client, fibaro_fgr223_shutter_state, integration
|
||||||
|
) -> None:
|
||||||
|
"""Test absence of tilt function for Fibaro Shutter roller blind.
|
||||||
|
|
||||||
|
Fibaro Shutter devices can have operating mode set to roller blind (1).
|
||||||
|
"""
|
||||||
|
node_state = replace_value_of_zwave_value(
|
||||||
|
fibaro_fgr223_shutter_state,
|
||||||
|
[
|
||||||
|
ZwaveValueMatcher(
|
||||||
|
property_=151,
|
||||||
|
command_class=CommandClass.CONFIGURATION,
|
||||||
|
endpoint=0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
node = Node(client, node_state)
|
||||||
|
client.driver.controller.emit("node added", {"node": node})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(FIBARO_FGR_223_SHUTTER_COVER_ENTITY)
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_OPEN
|
||||||
|
assert ATTR_CURRENT_POSITION in state.attributes
|
||||||
|
assert ATTR_CURRENT_TILT_POSITION not in state.attributes
|
||||||
|
|
||||||
|
|
||||||
async def test_iblinds_v3_cover(
|
async def test_iblinds_v3_cover(
|
||||||
hass: HomeAssistant, client, iblinds_v3, integration
|
hass: HomeAssistant, client, iblinds_v3, integration
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user