diff --git a/homeassistant/components/niko_home_control/light.py b/homeassistant/components/niko_home_control/light.py index c9902cbf11b..69d4e71c755 100644 --- a/homeassistant/components/niko_home_control/light.py +++ b/homeassistant/components/niko_home_control/light.py @@ -108,6 +108,7 @@ class NikoHomeControlLight(NikoHomeControlEntity, LightEntity): if action.is_dimmable: self._attr_color_mode = ColorMode.BRIGHTNESS self._attr_supported_color_modes = {ColorMode.BRIGHTNESS} + self._attr_brightness = round(action.state * 2.55) def turn_on(self, **kwargs: Any) -> None: """Instruct the light to turn on.""" diff --git a/tests/components/niko_home_control/conftest.py b/tests/components/niko_home_control/conftest.py index 63307a88e8a..b3dedd0c182 100644 --- a/tests/components/niko_home_control/conftest.py +++ b/tests/components/niko_home_control/conftest.py @@ -3,6 +3,7 @@ from collections.abc import Generator from unittest.mock import AsyncMock, patch +from nhc.light import NHCLight import pytest from homeassistant.components.niko_home_control.const import DOMAIN @@ -22,16 +23,48 @@ def mock_setup_entry() -> Generator[AsyncMock]: @pytest.fixture -def mock_niko_home_control_connection() -> Generator[AsyncMock]: +def light() -> NHCLight: + """Return a light mock.""" + mock = AsyncMock(spec=NHCLight) + mock.id = 1 + mock.type = 1 + mock.is_dimmable = False + mock.name = "light" + mock.suggested_area = "room" + mock.state = 100 + return mock + + +@pytest.fixture +def dimmable_light() -> NHCLight: + """Return a dimmable light mock.""" + mock = AsyncMock(spec=NHCLight) + mock.id = 2 + mock.type = 2 + mock.is_dimmable = True + mock.name = "dimmable light" + mock.suggested_area = "room" + mock.state = 100 + return mock + + +@pytest.fixture +def mock_niko_home_control_connection( + light: NHCLight, dimmable_light: NHCLight +) -> Generator[AsyncMock]: """Mock a NHC client.""" with ( patch( - "homeassistant.components.niko_home_control.config_flow.NHCController", + "homeassistant.components.niko_home_control.NHCController", autospec=True, ) as mock_client, + patch( + "homeassistant.components.niko_home_control.config_flow.NHCController", + new=mock_client, + ), ): client = mock_client.return_value - client.return_value = True + client.lights = [light, dimmable_light] yield client @@ -39,5 +72,8 @@ def mock_niko_home_control_connection() -> Generator[AsyncMock]: def mock_config_entry() -> MockConfigEntry: """Return the default mocked config entry.""" return MockConfigEntry( - domain=DOMAIN, title="Niko Home Control", data={CONF_HOST: "192.168.0.123"} + domain=DOMAIN, + title="Niko Home Control", + data={CONF_HOST: "192.168.0.123"}, + entry_id="01JFN93M7KRA38V5AMPCJ2JYYV", ) diff --git a/tests/components/niko_home_control/snapshots/test_light.ambr b/tests/components/niko_home_control/snapshots/test_light.ambr new file mode 100644 index 00000000000..702b7326ee2 --- /dev/null +++ b/tests/components/niko_home_control/snapshots/test_light.ambr @@ -0,0 +1,112 @@ +# serializer version: 1 +# name: test_entities[light.dimmable_light-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'supported_color_modes': list([ + , + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'light', + 'entity_category': None, + 'entity_id': 'light.dimmable_light', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'niko_home_control', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01JFN93M7KRA38V5AMPCJ2JYYV-2', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[light.dimmable_light-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'brightness': 255, + 'color_mode': , + 'friendly_name': 'dimmable light', + 'supported_color_modes': list([ + , + ]), + 'supported_features': , + }), + 'context': , + 'entity_id': 'light.dimmable_light', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_entities[light.light-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'supported_color_modes': list([ + , + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'light', + 'entity_category': None, + 'entity_id': 'light.light', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'niko_home_control', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01JFN93M7KRA38V5AMPCJ2JYYV-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[light.light-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'color_mode': , + 'friendly_name': 'light', + 'supported_color_modes': list([ + , + ]), + 'supported_features': , + }), + 'context': , + 'entity_id': 'light.light', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/niko_home_control/test_light.py b/tests/components/niko_home_control/test_light.py new file mode 100644 index 00000000000..801bdf6a296 --- /dev/null +++ b/tests/components/niko_home_control/test_light.py @@ -0,0 +1,138 @@ +"""Tests for the Niko Home Control Light platform.""" + +from typing import Any +from unittest.mock import AsyncMock, patch + +import pytest +from syrupy import SnapshotAssertion + +from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_OFF, + STATE_ON, + Platform, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +async def test_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + mock_niko_home_control_connection: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + with patch( + "homeassistant.components.niko_home_control.PLATFORMS", [Platform.LIGHT] + ): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +@pytest.mark.parametrize( + ("light_id", "data", "set_brightness"), + [ + (0, {ATTR_ENTITY_ID: "light.light"}, 100.0), + ( + 1, + {ATTR_ENTITY_ID: "light.dimmable_light", ATTR_BRIGHTNESS: 50}, + 19.607843137254903, + ), + ], +) +async def test_turning_on( + hass: HomeAssistant, + mock_niko_home_control_connection: AsyncMock, + mock_config_entry: MockConfigEntry, + light_id: int, + data: dict[str, Any], + set_brightness: int, +) -> None: + """Test turning on the light.""" + await setup_integration(hass, mock_config_entry) + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + data, + blocking=True, + ) + mock_niko_home_control_connection.lights[light_id].turn_on.assert_called_once_with( + set_brightness + ) + + +@pytest.mark.parametrize( + ("light_id", "entity_id"), + [ + (0, "light.light"), + (1, "light.dimmable_light"), + ], +) +async def test_turning_off( + hass: HomeAssistant, + mock_niko_home_control_connection: AsyncMock, + mock_config_entry: MockConfigEntry, + light_id: int, + entity_id: str, +) -> None: + """Test turning on the light.""" + await setup_integration(hass, mock_config_entry) + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + mock_niko_home_control_connection.lights[ + light_id + ].turn_off.assert_called_once_with() + + +async def test_updating( + hass: HomeAssistant, + mock_niko_home_control_connection: AsyncMock, + mock_config_entry: MockConfigEntry, + light: AsyncMock, + dimmable_light: AsyncMock, +) -> None: + """Test turning on the light.""" + await setup_integration(hass, mock_config_entry) + + assert hass.states.get("light.light").state == STATE_ON + + light.state = 0 + await mock_niko_home_control_connection.register_callback.call_args_list[0][0][1](0) + await hass.async_block_till_done() + + assert hass.states.get("light.light").state == STATE_OFF + + assert hass.states.get("light.dimmable_light").state == STATE_ON + assert hass.states.get("light.dimmable_light").attributes[ATTR_BRIGHTNESS] == 255 + + dimmable_light.state = 80 + await mock_niko_home_control_connection.register_callback.call_args_list[1][0][1]( + 80 + ) + await hass.async_block_till_done() + + assert hass.states.get("light.dimmable_light").state == STATE_ON + assert hass.states.get("light.dimmable_light").attributes[ATTR_BRIGHTNESS] == 204 + + dimmable_light.state = 0 + await mock_niko_home_control_connection.register_callback.call_args_list[1][0][1](0) + await hass.async_block_till_done() + + assert hass.states.get("light.dimmable_light").state == STATE_OFF + assert hass.states.get("light.dimmable_light").attributes[ATTR_BRIGHTNESS] is None