mirror of
https://github.com/home-assistant/core.git
synced 2026-02-15 07:36:16 +00:00
Bump pyvlx to 0.2.29 (#162829)
This commit is contained in:
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pyvlx import Intensity, Light
|
||||
from pyvlx import Intensity, Light, OnOffLight
|
||||
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -26,7 +26,7 @@ async def async_setup_entry(
|
||||
async_add_entities(
|
||||
VeluxLight(node, config_entry.entry_id)
|
||||
for node in pyvlx.nodes
|
||||
if isinstance(node, Light)
|
||||
if isinstance(node, (Light, OnOffLight))
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class VeluxLight(VeluxEntity, LightEntity):
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the current brightness."""
|
||||
return int((100 - self.node.intensity.intensity_percent) * 255 / 100)
|
||||
return int(self.node.intensity.intensity_percent * 255 / 100)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
@@ -53,7 +53,7 @@ class VeluxLight(VeluxEntity, LightEntity):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn on."""
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
intensity_percent = int(100 - kwargs[ATTR_BRIGHTNESS] / 255 * 100)
|
||||
intensity_percent = int(kwargs[ATTR_BRIGHTNESS] / 255 * 100)
|
||||
await self.node.set_intensity(
|
||||
Intensity(intensity_percent=intensity_percent),
|
||||
wait_for_completion=True,
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["pyvlx"],
|
||||
"requirements": ["pyvlx==0.2.28"]
|
||||
"requirements": ["pyvlx==0.2.29"]
|
||||
}
|
||||
|
||||
2
requirements_all.txt
generated
2
requirements_all.txt
generated
@@ -2682,7 +2682,7 @@ pyvesync==3.4.1
|
||||
pyvizio==0.1.61
|
||||
|
||||
# homeassistant.components.velux
|
||||
pyvlx==0.2.28
|
||||
pyvlx==0.2.29
|
||||
|
||||
# homeassistant.components.volumio
|
||||
pyvolumio==0.1.5
|
||||
|
||||
2
requirements_test_all.txt
generated
2
requirements_test_all.txt
generated
@@ -2260,7 +2260,7 @@ pyvesync==3.4.1
|
||||
pyvizio==0.1.61
|
||||
|
||||
# homeassistant.components.velux
|
||||
pyvlx==0.2.28
|
||||
pyvlx==0.2.29
|
||||
|
||||
# homeassistant.components.volumio
|
||||
pyvolumio==0.1.5
|
||||
|
||||
@@ -4,11 +4,9 @@ from collections.abc import Generator
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from pyvlx.lightening_device import Light
|
||||
from pyvlx.opening_device import Blind, Window
|
||||
from pyvlx import Blind, Light, OnOffLight, Scene, Window
|
||||
|
||||
from homeassistant.components.velux import DOMAIN
|
||||
from homeassistant.components.velux.scene import PyVLXScene as Scene
|
||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
@@ -104,6 +102,18 @@ def mock_light() -> AsyncMock:
|
||||
return light
|
||||
|
||||
|
||||
# a light without intensity support (e.g., a simple on/off light)
|
||||
@pytest.fixture
|
||||
def mock_onoff_light() -> AsyncMock:
|
||||
"""Create a mock Velux light."""
|
||||
light = AsyncMock(spec=OnOffLight, autospec=True)
|
||||
light.name = "Test On Off Light"
|
||||
light.serial_number = "0816"
|
||||
light.intensity = MagicMock()
|
||||
light.pyvlx = MagicMock()
|
||||
return light
|
||||
|
||||
|
||||
# fixture to create all other cover types via parameterization
|
||||
@pytest.fixture
|
||||
def mock_cover_type(request: pytest.FixtureRequest) -> AsyncMock:
|
||||
@@ -122,6 +132,7 @@ def mock_cover_type(request: pytest.FixtureRequest) -> AsyncMock:
|
||||
def mock_pyvlx(
|
||||
mock_scene: AsyncMock,
|
||||
mock_light: AsyncMock,
|
||||
mock_onoff_light: AsyncMock,
|
||||
mock_window: AsyncMock,
|
||||
mock_blind: AsyncMock,
|
||||
request: pytest.FixtureRequest,
|
||||
@@ -138,7 +149,13 @@ def mock_pyvlx(
|
||||
if hasattr(request, "param"):
|
||||
pyvlx.nodes = [request.getfixturevalue(request.param)]
|
||||
else:
|
||||
pyvlx.nodes = [mock_light, mock_blind, mock_window, mock_cover_type]
|
||||
pyvlx.nodes = [
|
||||
mock_light,
|
||||
mock_onoff_light,
|
||||
mock_blind,
|
||||
mock_window,
|
||||
mock_cover_type,
|
||||
]
|
||||
|
||||
pyvlx.scenes = [mock_scene]
|
||||
|
||||
|
||||
119
tests/components/velux/snapshots/test_light.ambr
Normal file
119
tests/components/velux/snapshots/test_light.ambr
Normal file
@@ -0,0 +1,119 @@
|
||||
# serializer version: 1
|
||||
# name: test_light_setup[mock_light][light.test_light-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'supported_color_modes': list([
|
||||
<ColorMode.BRIGHTNESS: 'brightness'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'light',
|
||||
'entity_category': None,
|
||||
'entity_id': 'light.test_light',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'velux',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '0815',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_light_setup[mock_light][light.test_light-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'brightness': None,
|
||||
'color_mode': None,
|
||||
'friendly_name': 'Test Light',
|
||||
'supported_color_modes': list([
|
||||
<ColorMode.BRIGHTNESS: 'brightness'>,
|
||||
]),
|
||||
'supported_features': <LightEntityFeature: 0>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'light.test_light',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_light_setup[mock_onoff_light][light.test_on_off_light-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'supported_color_modes': list([
|
||||
<ColorMode.BRIGHTNESS: 'brightness'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'light',
|
||||
'entity_category': None,
|
||||
'entity_id': 'light.test_on_off_light',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'velux',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '0816',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_light_setup[mock_onoff_light][light.test_on_off_light-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'brightness': None,
|
||||
'color_mode': None,
|
||||
'friendly_name': 'Test On Off Light',
|
||||
'supported_color_modes': list([
|
||||
<ColorMode.BRIGHTNESS: 'brightness'>,
|
||||
]),
|
||||
'supported_features': <LightEntityFeature: 0>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'light.test_on_off_light',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
@@ -16,7 +16,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
from . import update_callback_entity
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import MockConfigEntry, SnapshotAssertion, snapshot_platform
|
||||
|
||||
# Apply setup_integration fixture to all tests in this module
|
||||
pytestmark = pytest.mark.usefixtures("setup_integration")
|
||||
@@ -28,21 +28,34 @@ def platform() -> Platform:
|
||||
return Platform.LIGHT
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_pyvlx", ["mock_light", "mock_onoff_light"], indirect=True
|
||||
)
|
||||
async def test_light_setup(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Snapshot the entity and validate registry metadata for light entities."""
|
||||
await snapshot_platform(
|
||||
hass,
|
||||
entity_registry,
|
||||
snapshot,
|
||||
mock_config_entry.entry_id,
|
||||
)
|
||||
|
||||
|
||||
async def test_light_device_association(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mock_light: AsyncMock,
|
||||
) -> None:
|
||||
"""Test light entity setup and device association."""
|
||||
"""Test light device association."""
|
||||
|
||||
test_entity_id = f"light.{mock_light.name.lower().replace(' ', '_')}"
|
||||
|
||||
# Check that the entity exists and its name matches the node name (the light is the main feature).
|
||||
state = hass.states.get(test_entity_id)
|
||||
assert state is not None
|
||||
assert state.attributes.get("friendly_name") == mock_light.name
|
||||
|
||||
# Get entity + device entry
|
||||
entity_entry = entity_registry.async_get(test_entity_id)
|
||||
assert entity_entry is not None
|
||||
@@ -137,7 +150,7 @@ async def test_light_brightness_and_is_on(
|
||||
entity_id = f"light.{mock_light.name.lower().replace(' ', '_')}"
|
||||
|
||||
# Set initial intensity values
|
||||
mock_light.intensity.intensity_percent = 20 # 20% "intensity" -> 80% brightness
|
||||
mock_light.intensity.intensity_percent = 20 # 20% "intensity" -> 20% brightness
|
||||
mock_light.intensity.off = False
|
||||
mock_light.intensity.known = True
|
||||
|
||||
@@ -146,8 +159,8 @@ async def test_light_brightness_and_is_on(
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
# brightness = int((100 - 20) * 255 / 100) = int(204)
|
||||
assert state.attributes.get("brightness") == 204
|
||||
# brightness = int(20 * 255 / 100) = int(51)
|
||||
assert state.attributes.get("brightness") == 51
|
||||
assert state.state == "on"
|
||||
|
||||
# Mark as off
|
||||
@@ -161,7 +174,7 @@ async def test_light_brightness_and_is_on(
|
||||
async def test_light_turn_on_with_brightness_uses_set_intensity(
|
||||
hass: HomeAssistant, mock_light: AsyncMock
|
||||
) -> None:
|
||||
"""Turning on with brightness calls set_intensity with inverted percent."""
|
||||
"""Turning on with brightness calls set_intensity with percent."""
|
||||
|
||||
entity_id = f"light.{mock_light.name.lower().replace(' ', '_')}"
|
||||
|
||||
@@ -180,8 +193,8 @@ async def test_light_turn_on_with_brightness_uses_set_intensity(
|
||||
# Inspect the intensity argument (first positional)
|
||||
args, kwargs = mock_light.set_intensity.await_args
|
||||
intensity_obj = args[0]
|
||||
# brightness 51 -> 20% normalized -> intensity_percent = 80
|
||||
assert intensity_obj.intensity_percent == 80
|
||||
# brightness 51 -> 20% normalized -> intensity_percent = 20
|
||||
assert intensity_obj.intensity_percent == 20
|
||||
assert kwargs.get("wait_for_completion") is True
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user