Fix tilt controls for TiltOnlyVenetianBlind in Overkiz (#170055)

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Mick Vleeshouwer
2026-05-08 11:57:37 +02:00
committed by GitHub
co-authored by Copilot Autofix powered by AI
parent 70e18fc196
commit bb6087cf87
5 changed files with 197 additions and 23 deletions
+8 -1
View File
@@ -100,14 +100,21 @@ COVER_DESCRIPTIONS: list[OverkizCoverDescription] = [
close_tilt_command=OverkizCommand.LOWER_CLOSE,
stop_tilt_command=OverkizCommand.STOP,
),
# Needs override to remove open/close commands
# Needs override to add support for very specific tilt commands
# uiClass is VenetianBlind
OverkizCoverDescription(
key=UIWidget.TILT_ONLY_VENETIAN_BLIND,
device_class=CoverDeviceClass.BLIND,
is_closed_state=OverkizState.CORE_OPEN_CLOSED,
# Position commands fully open/close the tilt
open_command=OverkizCommand.OPEN,
close_command=OverkizCommand.CLOSE,
stop_command=OverkizCommand.STOP,
# Tilt commands move the tilt with a few degrees
open_tilt_command=OverkizCommand.TILT_POSITIVE,
open_tilt_command_args=(1, 0),
close_tilt_command=OverkizCommand.TILT_NEGATIVE,
close_tilt_command_args=(1, 0),
stop_tilt_command=OverkizCommand.STOP,
),
# Needs override to support very specific tilt commands (rts:ExteriorVenetianBlindRTSComponent)
@@ -20,6 +20,8 @@ COMMANDS_WITHOUT_DELAY = [
OverkizCommand.ON,
OverkizCommand.ON_WITH_TIMER,
OverkizCommand.TEST,
OverkizCommand.TILT_POSITIVE,
OverkizCommand.TILT_NEGATIVE,
]
@@ -323,6 +323,63 @@
"type": 1,
"oid": "ef870fe7-daf3-4f33-b91e-62b2a809ef4e",
"uiClass": "RollerShutter"
},
{
"creationTime": 1613676700000,
"lastUpdateTime": 1613676700000,
"label": "Jaloezie",
"deviceURL": "rts://1234-1234-6362/16730044",
"shortcut": false,
"controllableName": "rts:TiltOnlyVenetianBlindRTSComponent",
"definition": {
"commands": [
{
"commandName": "open",
"nparams": 0
},
{
"commandName": "close",
"nparams": 0
},
{
"commandName": "stop",
"nparams": 0
},
{
"commandName": "tiltPositive",
"nparams": 2
},
{
"commandName": "tiltNegative",
"nparams": 2
},
{
"commandName": "my",
"nparams": 1
},
{
"commandName": "identify",
"nparams": 0
}
],
"states": [],
"attributes": [],
"dataProperties": [],
"widgetName": "TiltOnlyVenetianBlind",
"uiProfiles": ["OpenClose"],
"uiClass": "VenetianBlind",
"qualifiedName": "rts:TiltOnlyVenetianBlindRTSComponent",
"type": "ACTUATOR"
},
"states": [],
"attributes": [],
"available": true,
"enabled": true,
"placeOID": "6133b4a0-f514-4553-b635-d1b7beb7e7b2",
"widget": "TiltOnlyVenetianBlind",
"type": 1,
"oid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"uiClass": "VenetianBlind"
}
],
"zones": [],
@@ -323,6 +323,60 @@
'state': 'open',
})
# ---
# name: test_cover_entities_snapshot[cloud_somfy_connexoon_rts_asia.json][cover.jaloezie-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.jaloezie',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.BLIND: 'blind'>,
'original_icon': None,
'original_name': None,
'platform': 'overkiz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 123>,
'translation_key': None,
'unique_id': 'rts://1234-1234-6362/16730044',
'unit_of_measurement': None,
})
# ---
# name: test_cover_entities_snapshot[cloud_somfy_connexoon_rts_asia.json][cover.jaloezie-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'assumed_state': True,
'device_class': 'blind',
'friendly_name': 'Jaloezie',
'is_closed': None,
'supported_features': <CoverEntityFeature: 123>,
}),
'context': <ANY>,
'entity_id': 'cover.jaloezie',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_cover_entities_snapshot[cloud_somfy_connexoon_rts_asia.json][cover.kitchen_shutter-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
+76 -22
View File
@@ -27,7 +27,12 @@ from homeassistant.components.cover import (
CoverEntityFeature,
CoverState,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import entity_registry as er
@@ -89,6 +94,11 @@ POSITIONABLE_DUAL_ROLLER_SHUTTER = FixtureDevice(
"io://1234-5678-5010/12931361",
"cover.basement_roller_shutter",
)
TILT_ONLY_VENETIAN_BLIND = FixtureDevice(
"setup/cloud_somfy_connexoon_rts_asia.json",
"rts://1234-1234-6362/16730044",
"cover.jaloezie",
)
DYNAMIC_GARAGE_DOOR = FixtureDevice(
"setup/cloud_somfy_tahoma_v2_europe.json",
"io://1234-1234-6233/16730050",
@@ -144,26 +154,62 @@ async def test_cover_entities_snapshot(
@pytest.mark.parametrize(
("device", "service", "command_name", "expected_state"),
("device", "service", "command_name", "parameters", "expected_state"),
[
(SHUTTER, SERVICE_OPEN_COVER, "open", CoverState.OPENING),
(AWNING, SERVICE_OPEN_COVER, "deploy", CoverState.OPENING),
(GARAGE, SERVICE_OPEN_COVER, "open", CoverState.OPENING),
(DYNAMIC_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", CoverState.OPENING),
(DYNAMIC_GARAGE_DOOR_OGP, SERVICE_OPEN_COVER, "open", CoverState.OPENING),
(PARTIAL_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", CoverState.OPENING),
(SHUTTER, SERVICE_CLOSE_COVER, "close", CoverState.CLOSING),
(AWNING, SERVICE_CLOSE_COVER, "undeploy", CoverState.CLOSING),
(GARAGE, SERVICE_CLOSE_COVER, "close", CoverState.CLOSING),
(DYNAMIC_GARAGE_DOOR, SERVICE_CLOSE_COVER, "close", CoverState.CLOSING),
(DYNAMIC_GARAGE_DOOR_OGP, SERVICE_CLOSE_COVER, "close", CoverState.CLOSING),
(PARTIAL_GARAGE_DOOR, SERVICE_CLOSE_COVER, "close", CoverState.CLOSING),
(SHUTTER, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(AWNING, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(GARAGE, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(DYNAMIC_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(DYNAMIC_GARAGE_DOOR_OGP, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(PARTIAL_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", CoverState.CLOSED),
(SHUTTER, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING),
(AWNING, SERVICE_OPEN_COVER, "deploy", None, CoverState.OPENING),
(GARAGE, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING),
(DYNAMIC_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING),
(DYNAMIC_GARAGE_DOOR_OGP, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING),
(PARTIAL_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING),
(TILT_ONLY_VENETIAN_BLIND, SERVICE_OPEN_COVER, "open", [0], CoverState.OPENING),
(SHUTTER, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING),
(AWNING, SERVICE_CLOSE_COVER, "undeploy", None, CoverState.CLOSING),
(GARAGE, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING),
(DYNAMIC_GARAGE_DOOR, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING),
(
DYNAMIC_GARAGE_DOOR_OGP,
SERVICE_CLOSE_COVER,
"close",
None,
CoverState.CLOSING,
),
(PARTIAL_GARAGE_DOOR, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING),
(
TILT_ONLY_VENETIAN_BLIND,
SERVICE_CLOSE_COVER,
"close",
[0],
CoverState.CLOSING,
),
(SHUTTER, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(AWNING, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(GARAGE, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(DYNAMIC_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(DYNAMIC_GARAGE_DOOR_OGP, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(PARTIAL_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED),
(TILT_ONLY_VENETIAN_BLIND, SERVICE_STOP_COVER, "stop", [0], STATE_UNKNOWN),
(
TILT_ONLY_VENETIAN_BLIND,
SERVICE_OPEN_COVER_TILT,
"tiltPositive",
[1, 0],
CoverState.OPENING,
),
(
TILT_ONLY_VENETIAN_BLIND,
SERVICE_CLOSE_COVER_TILT,
"tiltNegative",
[1, 0],
CoverState.CLOSING,
),
(
TILT_ONLY_VENETIAN_BLIND,
SERVICE_STOP_COVER_TILT,
"stop",
[0],
STATE_UNKNOWN,
),
],
ids=[
"open-roller-shutter",
@@ -172,18 +218,24 @@ async def test_cover_entities_snapshot(
"open-dynamic-garage-door",
"open-dynamic-garage-door-ogp",
"open-partial-garage-door",
"open-tilt-only-venetian-blind",
"close-roller-shutter",
"close-awning",
"close-garage-door",
"close-dynamic-garage-door",
"close-dynamic-garage-door-ogp",
"close-partial-garage-door",
"close-tilt-only-venetian-blind",
"stop-roller-shutter",
"stop-awning",
"stop-garage-door",
"stop-dynamic-garage-door",
"stop-dynamic-garage-door-ogp",
"stop-partial-garage-door",
"stop-tilt-only-venetian-blind",
"open-tilt-tilt-only-venetian-blind",
"close-tilt-tilt-only-venetian-blind",
"stop-tilt-tilt-only-venetian-blind",
],
)
async def test_cover_service_actions(
@@ -193,9 +245,10 @@ async def test_cover_service_actions(
device: FixtureDevice,
service: str,
command_name: str,
expected_state: CoverState,
parameters: list[Any] | None,
expected_state: CoverState | str,
) -> None:
"""Test open, close, and stop cover services."""
"""Test open, close, and stop cover and tilt services."""
await setup_overkiz_integration(fixture=device.fixture)
await hass.services.async_call(
@@ -212,6 +265,7 @@ async def test_cover_service_actions(
mock_client,
device_url=device.device_url,
command_name=command_name,
parameters=parameters,
)