mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Fix tilt calculation for HomeKit cover devices (#123532)
This commit is contained in:
parent
d7d35f74f2
commit
32f75597a9
@ -214,34 +214,32 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
|||||||
@property
|
@property
|
||||||
def current_cover_tilt_position(self) -> int | None:
|
def current_cover_tilt_position(self) -> int | None:
|
||||||
"""Return current position of cover tilt."""
|
"""Return current position of cover tilt."""
|
||||||
tilt_position = self.service.value(CharacteristicsTypes.VERTICAL_TILT_CURRENT)
|
|
||||||
if not tilt_position:
|
|
||||||
tilt_position = self.service.value(
|
|
||||||
CharacteristicsTypes.HORIZONTAL_TILT_CURRENT
|
|
||||||
)
|
|
||||||
if tilt_position is None:
|
|
||||||
return None
|
|
||||||
# Recalculate to convert from arcdegree scale to percentage scale.
|
|
||||||
if self.is_vertical_tilt:
|
if self.is_vertical_tilt:
|
||||||
scale = 0.9
|
char = self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT]
|
||||||
if (
|
|
||||||
self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT].minValue == -90
|
|
||||||
and self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT].maxValue
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
scale = -0.9
|
|
||||||
tilt_position = int(tilt_position / scale)
|
|
||||||
elif self.is_horizontal_tilt:
|
elif self.is_horizontal_tilt:
|
||||||
scale = 0.9
|
char = self.service[CharacteristicsTypes.HORIZONTAL_TILT_CURRENT]
|
||||||
if (
|
else:
|
||||||
self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].minValue
|
return None
|
||||||
== -90
|
|
||||||
and self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].maxValue
|
# Recalculate tilt_position. Convert arc to percent scale based on min/max values.
|
||||||
== 0
|
tilt_position = char.value
|
||||||
):
|
min_value = char.minValue
|
||||||
scale = -0.9
|
max_value = char.maxValue
|
||||||
tilt_position = int(tilt_position / scale)
|
total_range = int(max_value or 0) - int(min_value or 0)
|
||||||
return tilt_position
|
|
||||||
|
if (
|
||||||
|
tilt_position is None
|
||||||
|
or min_value is None
|
||||||
|
or max_value is None
|
||||||
|
or total_range <= 0
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# inverted scale
|
||||||
|
if min_value == -90 and max_value == 0:
|
||||||
|
return abs(int(100 / total_range * (tilt_position - max_value)))
|
||||||
|
# normal scale
|
||||||
|
return abs(int(100 / total_range * (tilt_position - min_value)))
|
||||||
|
|
||||||
async def async_stop_cover(self, **kwargs: Any) -> None:
|
async def async_stop_cover(self, **kwargs: Any) -> None:
|
||||||
"""Send hold command."""
|
"""Send hold command."""
|
||||||
@ -265,34 +263,32 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
|||||||
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
|
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
|
||||||
"""Move the cover tilt to a specific position."""
|
"""Move the cover tilt to a specific position."""
|
||||||
tilt_position = kwargs[ATTR_TILT_POSITION]
|
tilt_position = kwargs[ATTR_TILT_POSITION]
|
||||||
|
|
||||||
if self.is_vertical_tilt:
|
if self.is_vertical_tilt:
|
||||||
# Recalculate to convert from percentage scale to arcdegree scale.
|
char = self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET]
|
||||||
scale = 0.9
|
|
||||||
if (
|
|
||||||
self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET].minValue == -90
|
|
||||||
and self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET].maxValue
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
scale = -0.9
|
|
||||||
tilt_position = int(tilt_position * scale)
|
|
||||||
await self.async_put_characteristics(
|
|
||||||
{CharacteristicsTypes.VERTICAL_TILT_TARGET: tilt_position}
|
|
||||||
)
|
|
||||||
elif self.is_horizontal_tilt:
|
elif self.is_horizontal_tilt:
|
||||||
# Recalculate to convert from percentage scale to arcdegree scale.
|
char = self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET]
|
||||||
scale = 0.9
|
|
||||||
if (
|
# Calculate tilt_position. Convert from 1-100 scale to arc degree scale respecting possible min/max Values.
|
||||||
self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].minValue
|
min_value = char.minValue
|
||||||
== -90
|
max_value = char.maxValue
|
||||||
and self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].maxValue
|
if min_value is None or max_value is None:
|
||||||
== 0
|
raise ValueError(
|
||||||
):
|
"Entity does not provide minValue and maxValue for the tilt"
|
||||||
scale = -0.9
|
|
||||||
tilt_position = int(tilt_position * scale)
|
|
||||||
await self.async_put_characteristics(
|
|
||||||
{CharacteristicsTypes.HORIZONTAL_TILT_TARGET: tilt_position}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# inverted scale
|
||||||
|
if min_value == -90 and max_value == 0:
|
||||||
|
tilt_position = int(
|
||||||
|
tilt_position / 100 * (min_value - max_value) + max_value
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tilt_position = int(
|
||||||
|
tilt_position / 100 * (max_value - min_value) + min_value
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.async_put_characteristics({char.type: tilt_position})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, Any]:
|
def extra_state_attributes(self) -> dict[str, Any]:
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"aid": 1,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"iid": 1,
|
||||||
|
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 2,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Internal Cover",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 3,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Netatmo",
|
||||||
|
"description": "Manufacturer",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 4,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Internal Cover",
|
||||||
|
"description": "Model",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 5,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "**REDACTED**",
|
||||||
|
"description": "Serial Number",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 7,
|
||||||
|
"perms": ["pw"],
|
||||||
|
"format": "bool",
|
||||||
|
"description": "Identify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 6,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "0.0.0",
|
||||||
|
"description": "Firmware Revision",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000220-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 15,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "data",
|
||||||
|
"value": "+nvrOv1cCQU="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 8,
|
||||||
|
"type": "0000008C-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 9,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Venetian Blinds",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000007C-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 11,
|
||||||
|
"perms": ["pr", "pw", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Target Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000006D-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 10,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Current Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000072-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 12,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 2,
|
||||||
|
"description": "Position State",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 2,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000006C-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 13,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "int",
|
||||||
|
"value": 90,
|
||||||
|
"description": "Current Horizontal Tilt Angle",
|
||||||
|
"unit": "arcdegrees",
|
||||||
|
"minValue": -90,
|
||||||
|
"maxValue": 90,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000007B-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 14,
|
||||||
|
"perms": ["pr", "pw", "ev"],
|
||||||
|
"format": "int",
|
||||||
|
"value": 90,
|
||||||
|
"description": "Target Horizontal Tilt Angle",
|
||||||
|
"unit": "arcdegrees",
|
||||||
|
"minValue": -90,
|
||||||
|
"maxValue": 90,
|
||||||
|
"minStep": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,162 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"aid": 1,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"iid": 1,
|
||||||
|
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 2,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Sensor",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 3,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Netatmo",
|
||||||
|
"description": "Manufacturer",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 4,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Sensor",
|
||||||
|
"description": "Model",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 5,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "**REDACTED**",
|
||||||
|
"description": "Serial Number",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 7,
|
||||||
|
"perms": ["pw"],
|
||||||
|
"format": "bool",
|
||||||
|
"description": "Identify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 6,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "16.0.0",
|
||||||
|
"description": "Firmware Revision",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000220-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 18,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "data",
|
||||||
|
"value": "+nvrOv1cCQU="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 8,
|
||||||
|
"type": "0000008A-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 9,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Temperature sensor",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000011-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 10,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "float",
|
||||||
|
"value": 23.9,
|
||||||
|
"description": "Current Temperature",
|
||||||
|
"unit": "celsius",
|
||||||
|
"minValue": 0.0,
|
||||||
|
"maxValue": 50.0,
|
||||||
|
"minStep": 0.1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 11,
|
||||||
|
"type": "00000082-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 12,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Humidity sensor",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000010-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 13,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "float",
|
||||||
|
"value": 69.0,
|
||||||
|
"description": "Current Relative Humidity",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0.0,
|
||||||
|
"maxValue": 100.0,
|
||||||
|
"minStep": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 14,
|
||||||
|
"type": "00000097-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 15,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Carbon Dioxide sensor",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000092-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 16,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Carbon Dioxide Detected",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 1,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000093-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 17,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "float",
|
||||||
|
"value": 1124.0,
|
||||||
|
"description": "Carbon Dioxide Level",
|
||||||
|
"minValue": 0.0,
|
||||||
|
"maxValue": 5000.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
122
tests/components/homekit_controller/fixtures/velux_window.json
Normal file
122
tests/components/homekit_controller/fixtures/velux_window.json
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"aid": 1,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"iid": 1,
|
||||||
|
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 2,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Window",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 3,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Netatmo",
|
||||||
|
"description": "Manufacturer",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 4,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX Window",
|
||||||
|
"description": "Model",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 5,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "**REDACTED**",
|
||||||
|
"description": "Serial Number",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 7,
|
||||||
|
"perms": ["pw"],
|
||||||
|
"format": "bool",
|
||||||
|
"description": "Identify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 6,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "0.0.0",
|
||||||
|
"description": "Firmware Revision",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000220-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 13,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "data",
|
||||||
|
"value": "+nvrOv1cCQU="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 8,
|
||||||
|
"type": "0000008B-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 9,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Roof Window",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000007C-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 11,
|
||||||
|
"perms": ["pr", "pw", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Target Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000006D-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 10,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Current Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000072-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 12,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 2,
|
||||||
|
"description": "Position State",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 2,
|
||||||
|
"minStep": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,122 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"aid": 1,
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"iid": 1,
|
||||||
|
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 2,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX External Cover",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 3,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Netatmo",
|
||||||
|
"description": "Manufacturer",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 4,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "VELUX External Cover",
|
||||||
|
"description": "Model",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 5,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "**REDACTED**",
|
||||||
|
"description": "Serial Number",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 7,
|
||||||
|
"perms": ["pw"],
|
||||||
|
"format": "bool",
|
||||||
|
"description": "Identify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 6,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "15.0.0",
|
||||||
|
"description": "Firmware Revision",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000220-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 13,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "data",
|
||||||
|
"value": "+nvrOv1cCQU="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iid": 8,
|
||||||
|
"type": "0000008C-0000-1000-8000-0026BB765291",
|
||||||
|
"characteristics": [
|
||||||
|
{
|
||||||
|
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 9,
|
||||||
|
"perms": ["pr"],
|
||||||
|
"format": "string",
|
||||||
|
"value": "Awning Blinds",
|
||||||
|
"description": "Name",
|
||||||
|
"maxLen": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000007C-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 11,
|
||||||
|
"perms": ["pr", "pw", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Target Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "0000006D-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 10,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Current Position",
|
||||||
|
"unit": "percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"minStep": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "00000072-0000-1000-8000-0026BB765291",
|
||||||
|
"iid": 12,
|
||||||
|
"perms": ["pr", "ev"],
|
||||||
|
"format": "uint8",
|
||||||
|
"value": 2,
|
||||||
|
"description": "Position State",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 2,
|
||||||
|
"minStep": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
@ -116,6 +116,32 @@ def create_window_covering_service_with_none_tilt(accessory: Accessory) -> None:
|
|||||||
tilt_target.maxValue = 0
|
tilt_target.maxValue = 0
|
||||||
|
|
||||||
|
|
||||||
|
def create_window_covering_service_with_no_minmax_tilt(accessory):
|
||||||
|
"""Apply use values (-90 to 90) if min/max not provided."""
|
||||||
|
service = create_window_covering_service(accessory)
|
||||||
|
|
||||||
|
tilt_current = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_CURRENT)
|
||||||
|
tilt_current.value = 0
|
||||||
|
|
||||||
|
tilt_target = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_TARGET)
|
||||||
|
tilt_target.value = 0
|
||||||
|
|
||||||
|
|
||||||
|
def create_window_covering_service_with_full_range_tilt(accessory):
|
||||||
|
"""Somfi Velux Integration."""
|
||||||
|
service = create_window_covering_service(accessory)
|
||||||
|
|
||||||
|
tilt_current = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_CURRENT)
|
||||||
|
tilt_current.value = 0
|
||||||
|
tilt_current.minValue = -90
|
||||||
|
tilt_current.maxValue = 90
|
||||||
|
|
||||||
|
tilt_target = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_TARGET)
|
||||||
|
tilt_target.value = 0
|
||||||
|
tilt_target.minValue = -90
|
||||||
|
tilt_target.maxValue = 90
|
||||||
|
|
||||||
|
|
||||||
async def test_change_window_cover_state(
|
async def test_change_window_cover_state(
|
||||||
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -267,6 +293,40 @@ async def test_read_window_cover_tilt_missing_tilt(
|
|||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_read_window_cover_tilt_full_range(
|
||||||
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
|
) -> None:
|
||||||
|
"""Test that horizontal tilt is handled correctly."""
|
||||||
|
helper = await setup_test_component(
|
||||||
|
hass, get_next_aid(), create_window_covering_service_with_full_range_tilt
|
||||||
|
)
|
||||||
|
|
||||||
|
await helper.async_update(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{CharacteristicsTypes.HORIZONTAL_TILT_CURRENT: 0},
|
||||||
|
)
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
# Expect converted value from arcdegree scale to percentage scale.
|
||||||
|
assert state.attributes["current_tilt_position"] == 50
|
||||||
|
|
||||||
|
|
||||||
|
async def test_read_window_cover_tilt_no_minmax(
|
||||||
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
|
) -> None:
|
||||||
|
"""Test that horizontal tilt is handled correctly."""
|
||||||
|
helper = await setup_test_component(
|
||||||
|
hass, get_next_aid(), create_window_covering_service_with_no_minmax_tilt
|
||||||
|
)
|
||||||
|
|
||||||
|
await helper.async_update(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{CharacteristicsTypes.HORIZONTAL_TILT_CURRENT: 90},
|
||||||
|
)
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
# Expect converted value from arcdegree scale to percentage scale.
|
||||||
|
assert state.attributes["current_tilt_position"] == 100
|
||||||
|
|
||||||
|
|
||||||
async def test_write_window_cover_tilt_horizontal(
|
async def test_write_window_cover_tilt_horizontal(
|
||||||
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -359,6 +419,29 @@ async def test_write_window_cover_tilt_vertical_2(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_write_window_cover_tilt_no_minmax(
|
||||||
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
|
) -> None:
|
||||||
|
"""Test that horizontal tilt is written correctly."""
|
||||||
|
helper = await setup_test_component(
|
||||||
|
hass, get_next_aid(), create_window_covering_service_with_no_minmax_tilt
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"set_cover_tilt_position",
|
||||||
|
{"entity_id": helper.entity_id, "tilt_position": 90},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
# Expect converted value from percentage scale to arcdegree scale.
|
||||||
|
helper.async_assert_service_values(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 72,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_window_cover_stop(
|
async def test_window_cover_stop(
|
||||||
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -378,6 +461,57 @@ async def test_window_cover_stop(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_write_window_cover_tilt_full_range(
|
||||||
|
hass: HomeAssistant, get_next_aid: Callable[[], int]
|
||||||
|
) -> None:
|
||||||
|
"""Test that full-range tilt is working correctly."""
|
||||||
|
helper = await setup_test_component(
|
||||||
|
hass, get_next_aid(), create_window_covering_service_with_full_range_tilt
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"set_cover_tilt_position",
|
||||||
|
{"entity_id": helper.entity_id, "tilt_position": 10},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
# Expect converted value from percentage scale to arc on -90 to +90 scale.
|
||||||
|
helper.async_assert_service_values(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.HORIZONTAL_TILT_TARGET: -72,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"set_cover_tilt_position",
|
||||||
|
{"entity_id": helper.entity_id, "tilt_position": 50},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
# Expect converted value from percentage scale to arc on -90 to +90 scale.
|
||||||
|
helper.async_assert_service_values(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"set_cover_tilt_position",
|
||||||
|
{"entity_id": helper.entity_id, "tilt_position": 90},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
# Expect converted value from percentage scale to arc on -90 to +90 scale.
|
||||||
|
helper.async_assert_service_values(
|
||||||
|
ServicesTypes.WINDOW_COVERING,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 72,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_garage_door_opener_service(accessory: Accessory) -> None:
|
def create_garage_door_opener_service(accessory: Accessory) -> None:
|
||||||
"""Define a garage-door-opener chars as per page 217 of HAP spec."""
|
"""Define a garage-door-opener chars as per page 217 of HAP spec."""
|
||||||
service = accessory.add_service(ServicesTypes.GARAGE_DOOR_OPENER)
|
service = accessory.add_service(ServicesTypes.GARAGE_DOOR_OPENER)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user